Skip to main content
Version: 9.x

Make a PDF conform

Repairs a PDF until it conforms to PDF/A, PDF/UA or Factur-X, or to PDF/A and PDF/UA together, and reports what it couldn't fix.

POST/forms/pdf/remediate
filesfile[]required

The PDFs, and the files the options name.

archivesfile[]

ZIP files Gotenberg unpacks: each entry counts as a file uploaded under files.

URLs Gotenberg downloads first, as if you had uploaded the files. Each entry takes a url, and optionally extraHttpHeaders.

profilestring or listrequired

PDF/A-1a, PDF/A-1b, PDF/A-2a, PDF/A-2b, PDF/A-2u, PDF/A-3a, PDF/A-3b, PDF/A-3u, PDF/A-4, PDF/A-4e, PDF/A-4f, PDF/UA-1, PDF/UA-2 or Factur-X. A list pairs a PDF/A profile, or Factur-X, with the PDF/UA profile of its PDF version: PDF/A-1 to PDF/A-3 with PDF/UA-1, PDF/A-4 with PDF/UA-2.

languagestring

The document's language, as a BCP 47 tag such as de-DE.

Default: en

aggressiveboolean

Allows fixes that may change how pages look, for better compliance.

Default: false

The alternate text for figures that lack one.

xmlfile

Factur-X only: the uploaded invoice XML to embed. Without it, Factur-X repairs the invoice the PDF already carries.

levelstring

Factur-X with xml, required: MINIMUM, BASIC WL, BASIC, EN 16931, EXTENDED or XRECHNUNG.

Factur-X with xml: the document type written in the metadata.

Default: INVOICE

The PDF, or a ZIP of the PDFs when you send several.

The route also takes the headers. An error answers a status and a message: see Errors.

Remediate a PDF​

curl \
--request POST http://localhost:3000/forms/pdf/remediate \
--form files=@report.pdf \
--form profile=PDF/A-2b \
-o report.pdf
Response
HTTP/1.1 200 OK
Content-Type: application/pdf
Gotenberg-Remediation-Residual: 0
Gotenberg-Remediation-Rolled-Back: 0

Two headers report how it went:

  • Gotenberg-Remediation-Residual counts the violations left. 0 means the PDF conforms.
  • Gotenberg-Remediation-Rolled-Back counts the fixes Gotenberg undid because they lost pages, text or images. aggressive: true allows more fixes that may change how the pages look, for better compliance, under the same rollback. It deletes every embedded file on PDF/A-1, which forbids them, and the ones that aren't PDF/A themselves on PDF/A-2 and PDF/A-4, which forbid those.

Gotenberg answers 200 even when violations remain: check Gotenberg-Remediation-Residual, and list what's left with /forms/pdf/validate. With several PDFs, the headers sum their counts.

Pick a PDF/A level​

profile takes PDF/A-1a, PDF/A-1b, PDF/A-2a, PDF/A-2b, PDF/A-2u, PDF/A-3a, PDF/A-3b, PDF/A-3u, PDF/A-4, PDF/A-4e or PDF/A-4f.

  • The letter sets how much the PDF keeps: b its look, u its text as Unicode too, a its structure too, through tags.
  • The number sets the base: PDF/A-1 builds on PDF 1.4, PDF/A-2 adds transparency and layers, PDF/A-3 accepts embedded files of any type, and PDF/A-4 builds on PDF 2.0.

PDF/A-4f needs an embedded file: attach one first, or the residual stays above 0.

Pick the level your archive or portal asks for. Without one, PDF/A-4 is the latest version.

Make it PDF/UA​

PDF/UA-1 and PDF/UA-2 make the PDF accessible, and tag it if it isn't:

curl \
--request POST http://localhost:3000/forms/pdf/remediate \
--form files=@report.pdf \
--form profile=PDF/UA-1 \
--form language=en-US \
-o report.pdf
Response
HTTP/1.1 200 OK
Content-Type: application/pdf
Gotenberg-Remediation-Residual: 0
Gotenberg-Remediation-Rolled-Back: 0
  • language sets the document's language, en by default. Screen readers pick their voice from it.
  • figureAltText gives a description to the figures that lack one. Better, write the alt text in your HTML.

Make it PDF/A and PDF/UA​

A PDF can be archival and accessible at once. Give profile a PDF/A profile and a PDF/UA one, as a JSON array or as the field repeated:

curl \
--request POST http://localhost:3000/forms/pdf/remediate \
--form files=@report.pdf \
--form 'profile=[
"PDF/A-2b",
"PDF/UA-1"
]' \
--form language=en-US \
-o report.pdf
Response
HTTP/1.1 200 OK
Content-Type: application/pdf
Gotenberg-Remediation-Residual: 0
Gotenberg-Remediation-Rolled-Back: 0

In a list of stages, the array goes in the stage: {"op": "remediate", "profile": ["PDF/A-2b", "PDF/UA-1"]}. The residual counts the violations of both profiles, so 0 means the PDF conforms to each.

The PDF version sets the pairs. PDF/A-1, PDF/A-2, PDF/A-3 and Factur-X pair with PDF/UA-1, and PDF/A-4 with PDF/UA-2. Any other pair answers 400 and lists these.

Make it a Factur-X​

Factur-X embeds the invoice's XML and makes the PDF a PDF/A-3 e-invoice, the format Germany also publishes as ZUGFeRD:

curl \
--request POST http://localhost:3000/forms/pdf/remediate \
--form files=@report.pdf \
--form files=@invoice.xml \
--form profile=Factur-X \
--form xml=invoice.xml \
--form 'level=EN 16931' \
-o invoice.pdf

The XML is a Cross Industry Invoice (CII), the syntax Factur-X uses. It declares its level, and level names the same one: another level, or an XML that isn't a CII invoice, answers 400 before anything changes. An XRECHNUNG invoice also passes as BASIC, EN 16931 or EXTENDED. EN 16931 carries everything the European standard for e-invoices requires; MINIMUM and BASIC WL carry less, so check what your recipient accepts.

Stage 'remediate' failed on 'report.pdf': factur-x conformance level does not match the invoice XML: level "MINIMUM" given, but the invoice XML declares "EN 16931" (guideline ID "urn:cen.eu:en16931:2017")

The residual counts the fatal violations the invoice leaves, the ones /forms/pdf/validate reports: 0 means the invoice validates.

Without xml, the stage repairs a Factur-X invoice the PDF already carries. The e-invoice recipe makes one from HTML.

Remediate last​

A list takes one remediate, so a pair goes in one stage. It comes after the stages that change the content: only encrypt, optimize, sign, timestamp and render may follow it. A PDF/A or Factur-X can't be encrypted.

In a list of stages​

The stage also runs in a list on /forms/pdf/pipe, and on the PDFs a Chromium or LibreOffice conversion makes, in its stages field:

curl \
--request POST http://localhost:3000/forms/pdf/pipe \
--form files=@report.pdf \
--form 'stages=[
{ "op": "remediate", "profile": "PDF/A-4" }
]' \
-o report.pdf
Response
HTTP/1.1 200 OK
Content-Type: application/pdf
Gotenberg-Remediation-Residual: 0
Gotenberg-Remediation-Rolled-Back: 0