Skip to content

PDF standards, passwords and signatures

Give your PDFs a title, make them PDF/A or PDF/UA with bookmarks, embed e-invoice XML, and protect them with a password or a digital signature.

  • An editable template in Studio. See build a template.
  • curl or a client library for the API examples, set up as in the quickstart.

For what the standards require, see PDF/A, PDF/UA and Factur-X.

In Studio, open the template and click PDF properties (the sliders button) in the preview toolbar. Fill in Title, Author and the other fields under Document. Without a Title, the PDF takes the template’s name. Studio writes the fields into the template’s page.json:

{
"metadata": {
"title": "Invoice {{invoice.number}}",
"author": "Example Ltd"
}
}

{{invoice.number}} is filled from each render’s data. To change a property for one render, send metadata with the request:

Terminal window
curl -X POST "$PDF_URL/v1/renders" \
-H "x-api-key: $API_KEY" \
-H "content-type: application/json" \
-d '{
"templateVersionId": "0b7d5c1e-8f3a-4d2b-9e61-5a4c3b2a1f00",
"data": { "invoice": { "number": "2026-0042" } },
"metadata": { "author": "Example Billing" }
}'

The curl call creates a render. Once it has succeeded, download the PDF from its result.downloadUrl. The clients wait and return the file.

The properties are title, author, subject, creator, producer (default typefold), language (default: the render’s language) and keywords. A value sent with a request replaces the template’s value for that property. An empty string removes a property (producer and language go back to their defaults), and "keywords": [] removes the keywords. Only the template’s values fill {{path}} placeholders; request values are used as written.

In the preview toolbar, click the shield button (Check accessibility and conformance). Studio lists which PDF/A levels and PDF/UA parts the document meets and what to change for the others. It also lists accessibility problems in the HTML and the order a screen reader reads the PDF.

With the API, add "checkConformance": true to a template preview (POST /v1/templates/{id}/preview). The pdf-conformance response header lists each standard with conforms and, when it does not, the issues to fix. A preview render on POST /v1/renders returns the same list in result.conformance. See the API reference.

In PDF properties, under Standards, pick a level for PDF/A: PDF/A-2b for archiving, PDF/A-3b for e-invoices. Studio writes it into page.json:

{ "pdfa": "2b" }

Save the template and click Publish. Every render of the new version is now a PDF/A file at the level you picked.

The levels are 2b, 2u, 2a, 3b, 3u, 3a, 4 and 4f. To pick a level for one render, set pdf.pdfa in a Reports API request. A request cannot turn off the template’s level.

A PDF/UA document needs three things in the template:

  • a title (the template’s name, unless you set Title),
  • at least one heading (h1 to h6),
  • alternative text on every image: <img src="logo.png" alt="Example Ltd logo">.

Then, in PDF properties under Standards, set PDF/UA to PDF/UA-1. page.json now has both settings:

{ "pdfa": "2b", "pdfua": "1" }

Save the template and publish it. PDF/UA-1 pairs with the PDF/A-2 and PDF/A-3 levels, and PDF/UA-2 ("pdfua": "2") with 4 and 4f.

A PDF/UA document gets bookmarks (the PDF outline) from its headings: one per visible h1 to h6, titled with the heading’s text and nested by level. PDF/UA is the only way to get them: a plain or PDF/A-only document has none. Pages that other templates add before or after bring bookmarks for their own headings. A PDF/A or PDF/UA document cannot add an uploaded PDF file.

Set the invoice template to PDF/A-3b, save it and publish it. Then send the XML file factur-x.xml with each render as an attachment:

This example uses jq to put the file into the JSON body:

Terminal window
jq -n --rawfile xml factur-x.xml '{
templateVersionId: "0b7d5c1e-8f3a-4d2b-9e61-5a4c3b2a1f00",
data: { invoice: { number: "2026-0042", total: 1190.00 } },
waitMs: 10000,
attachments: [
{
name: "factur-x.xml",
content: $xml,
mimeType: "text/xml",
description: "Factur-X invoice",
relationship: "alternative"
}
]
}' | curl -X POST "$PDF_URL/v1/renders" \
-H "x-api-key: $API_KEY" \
-H "content-type: application/json" \
--data-binary @-
  • A render can embed up to 10 files, 5 MiB in total. Send text as content or bytes as contentBase64.
  • In a PDF/A file, every attachment needs mimeType and description. Only the levels 3b, 3u, 3a and 4f can embed files.

Factur-X also expects its XMP extension schema. Add it to the template’s page.json, with the Version and ConformanceLevel of your XML’s profile:

{
"metadata": {
"xmp": [
{
"name": "Factur-X PDF/A Extension Schema",
"prefix": "fx",
"namespace": "urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#",
"properties": [
{ "name": "DocumentType", "value": "INVOICE", "description": "Document type" },
{
"name": "DocumentFileName",
"value": "factur-x.xml",
"description": "Attached XML file"
},
{ "name": "Version", "value": "1.0", "description": "Factur-X version" },
{ "name": "ConformanceLevel", "value": "EN 16931", "description": "Factur-X profile" }
]
}
]
}
}

To make readers ask for a password before they open a PDF, or to stop them printing or copying it:

  1. Open the template in Studio, click PDF properties and find Security.

  2. Enter an Open password. {{customer.number}} uses each customer’s number from the render’s data.

  3. Optionally enter an Owner password, which lifts the restrictions, and choose what readers may do under Printing and Readers may.

    Studio writes the settings into page.json:

    {
    "encryption": {
    "openPassword": "{{customer.number}}",
    "permissions": { "copying": false }
    }
    }
  4. Save the template and click Publish. A rendered PDF now asks for the password.

  • The permissions are printing (highResolution, lowResolution or none), copying, modifying, annotating, fillingForms, documentAssembly and contentAccessibility. Each one you leave out is allowed.
  • Without an owner password, nobody can lift the restrictions.
  • A password holds at most 127 bytes.
  • PDF/A does not allow passwords or restrictions, and PDF/UA needs Screen readers (PDF/UA requires it) ticked under Readers may.
  • A request’s encryption changes the template’s settings for one render.

Upload a signing certificate once, then pick it in each template that signs.

  1. In Studio, open Manage → Signing certificates and click Upload certificate. Enter a Name, such as Company seal, choose the Certificate file (.p12 or .pfx) and enter its File password.

  2. Open the template, click PDF properties and, under Signature, choose the certificate as Certificate. Optionally fill in Reason, Location and Contact. Studio writes them into page.json:

    {
    "signature": {
    "certificate": "Company seal",
    "reason": "Invoice {{invoice.number}}"
    }
    }

    The PDF is signed invisibly. To show the signature on a page, turn on Visible signature field and set its Area, then draw the signature block (a stamp or a name) in that area of the template.

  3. Save the template and click Publish. PDF readers now show the signature and the signer’s name.

  • A signed PDF cannot have a password or be PDF/UA.
  • A request’s signature changes the template’s settings for one render. Its field places a visible signature: page, then xMm, yMm, widthMm and heightMm from the page’s top-left corner.

Everyone in the workspace sees the list under Manage → Signing certificates, with each certificate’s Signer, Issued by and Valid until. Only owners and admins can upload or delete one; see roles.

  • Templates find a certificate by its name, ignoring case, and names are unique in a workspace. A render that names a certificate the workspace does not have fails.
  • The file holds one RSA or EC private key with its certificate chain, at most 64 KiB. An expired certificate is refused at upload, and the key can never be read back.
  • Expiry: once Valid until has passed, the list marks the certificate Expired and renders that sign with it fail.
  • Renewal: upload the new file under a new name, choose it under Signature and publish. Or delete the old certificate and upload the new file under the same name: templates keep working without a new version, but renders that sign fail in between.
  • Deleting a certificate cannot be undone. Templates that sign with it fail to render until a certificate with the same name is uploaded.
  • Environments: certificates are not copied by an environment import. Upload one with the same name in each environment.
  • A workspace holds up to 50 certificates. To manage them with the API, use /v1/signing-certificates with a key that has the certificate:manage scope (listing needs only template:read); see the API reference.

A test render keeps every setting on this page. Its “TEST” watermark is marked as decoration, not content, and passwords and signatures work as usual. Don’t archive test PDFs.

A document that cannot meet the standard fails, and the error message lists what to change. Fix the template, or turn the standard off, and render again. A setting that cannot work together, such as a password on a PDF/A file, answers 400 BAD_REQUEST at once. See errors.