Portugal requires a qualified electronic signature, or a qualified electronic seal, on PDF invoices from 1 January 2027. Until 31 December 2026, unsigned PDF invoices are still accepted as electronic invoices for tax purposes under the transitional rule carried by the 2026 State Budget law, Lei n.º 73-A/2025, de 30 de dezembro. The underlying obligation comes from Decreto-Lei n.º 28/2019. For a development team, the technical requirement is small and the architectural consequence is large: once an invoice PDF is signed, its bytes are frozen, so a pipeline that regenerates PDFs on demand stops working.
This article covers the regulatory state as of 22 September 2026, the eIDAS vocabulary you need to read the rule correctly, the PAdES levels, and the pipeline changes. It is not a how-to on the signing libraries themselves: for the code-level mechanics of embedding a signature, see how to add a digital signature to a PDF.
What exactly does Portugal require from 2027?
From 1 January 2027, an invoice sent as a PDF must carry a qualified electronic signature or a qualified electronic seal to be treated as a valid electronic invoice under Portuguese tax law. The legal base is Decreto-Lei n.º 28/2019, whose article 12 lists the ways a taxpayer can guarantee authenticity of origin and integrity of content: a qualified electronic signature, a qualified electronic seal under Regulation (EU) No 910/2014, or an electronic data interchange (EDI) system.
The PDF-without-signature situation is a transitional exception to that list, not a permanent option. Each year since 2021 that exception has been renewed, and the 2026 State Budget law renewed it once more through 31 December 2026.
Publicly available secondary sources agree on the 1 January 2027 date and on Lei n.º 73-A/2025 as the budget law carrying it. I was not able to confirm the exact article number inside that law that contains the extension, so this article does not cite one. Verify the article reference with your Portuguese accountant or with the Autoridade Tributária before quoting it in internal documentation.
Two things that are already in force and unaffected by the postponement: certified invoicing software, and the ATCUD plus QR code on invoices. Those requirements have applied since 2023 and are separate from the signature question. The QES obligation adds a cryptographic layer on top of documents that already carry those codes.
How many times has this deadline moved?
The Portuguese QES requirement on PDF invoices has been postponed roughly once a year since 2021, which is the single most useful fact for planning. According to The Invoicing Hub, the obligation was first meant to apply on 1 July 2021 and has been pushed back every year since.
| Date in force | Instrument reported | Note |
|---|---|---|
| 1 July 2021 (original) | Decreto-Lei n.º 28/2019 regime | Never enforced |
| 31 March 2021 | Despacho n.º 437/2020-XXII | Early administrative extension |
| 31 December 2021 | Despacho n.º 260/2021-XXII | Second administrative extension |
| 31 December 2024 | State Budget law for 2024 | Reported by tax press |
| 31 December 2025 | Article 114 of Lei n.º 45-A/2024 | State Budget law for 2025 |
| 31 December 2026 | Lei n.º 73-A/2025 (2026 budget) | Current rule, QES from 1 Jan 2027 |
The two despachos come from the Ordem dos Contabilistas Certificados, a professional body rather than the tax authority itself. The intermediate years between 2021 and 2024 were also extended, but I could not pin each one to a specific instrument from a primary source, so the table above does not list them.
Read that history as a planning input, not as a prediction. A team that treats 2027 as certain and one that treats it as likely-to-slip should reach the same conclusion: the work is the same either way, and most of it is architecture rather than cryptography.
What is a qualified electronic signature under eIDAS?
A qualified electronic signature is an advanced electronic signature created by a qualified signature creation device and based on a qualified certificate for electronic signatures. That definition comes from article 3 of the eIDAS Regulation (EU) No 910/2014. Under article 25(2), a QES has the same legal effect as a handwritten signature across the EU.
The three tiers in the regulation are worth separating because vendors blur them.
| Tier | Certificate | Key storage | Legal effect |
|---|---|---|---|
| Simple electronic signature | None required | Anywhere | Admissible, no presumption |
| Advanced (AdES) | Any, linked to signatory | Signatory control, no device rule | Detects later changes |
| Qualified (QES) | Qualified certificate from a qualified TSP | QSCD (Annex II) | Equivalent to handwriting |
The practical gap between advanced and qualified is almost entirely about who issued the certificate and where the private key lives. A self-signed certificate on your build server can produce a cryptographically sound advanced signature and will never produce a qualified one.
A qualified electronic seal is the organisational counterpart: it belongs to a legal person rather than a natural one. For invoice issuance at volume, a seal is usually the right instrument, because nobody wants a named employee personally signing 40,000 invoices a month. Portuguese guidance accepts either.
The qualified trust service providers allowed to issue these certificates are published on the EU Trusted Lists. You cannot become one by configuring OpenSSL.
Which PAdES level should invoices use?
PAdES is the ETSI profile that defines how an advanced or qualified signature is embedded in a PDF. The baseline levels are specified in ETSI EN 319 142-1 and they stack: each level includes everything below it.
| Level | Adds | Why it matters for an invoice |
|---|---|---|
| B-B | Signature and signer certificate only | Minimal, no independent proof of when |
| B-T | Trusted timestamp from a TSA | Signing time no longer depends on the signer's clock |
| B-LT | Embedded validation material (certificates, CRL/OCSP) | Verifiable after the CA endpoints go away |
| B-LTA | Archival timestamps over the whole structure | Verifiable after the certificate and algorithms age out |
For a document that a tax authority may inspect years later, B-B is the wrong floor. B-T is the practical minimum because a timestamp from an RFC 3161 authority is the only thing proving the signature existed before a given moment. B-LT and B-LTA exist because certificates expire and revocation endpoints get retired, and a verifier in 2034 has no way to check a 2027 certificate unless the validation material travelled inside the file.
Portuguese tax law sets retention obligations measured in years, which is the argument for B-LT or B-LTA rather than B-T. Confirm the level your accountant or certified software vendor expects before committing, since the required level is a compliance decision, not a technical preference.
Why is a signature image worth nothing here?
A signature image pasted into a PDF page is pixels. It has no certificate, no key, no hash, and no relationship to the file's contents. Anyone can open the document, change the VAT amount, and the image sits there unchanged. Nothing in the file detects the edit.
A cryptographic signature works differently. The signer computes a hash over a byte range of the PDF, signs that hash with a private key, and writes the result into a signature dictionary inside the file, in PKCS#7/CMS form. A verifier recomputes the hash, checks it against the signature using the certificate's public key, and reports a mismatch the moment any covered byte changes.
This distinction decides whether your invoice pipeline is compliant. Teams that already "sign" invoices by stamping a PNG of a director's handwriting have done zero of the work required for 2027.
The same reasoning applies to flattening, watermarking or compressing a PDF after signing. Every one of those operations rewrites bytes, and every one of them breaks the signature. If you post-process invoices for storage, the post-processing has to happen before signing, never after.
Where does the private key actually live?
For a qualified signature the private key must live in a qualified signature creation device, and that rules out the pattern most teams reach for first. Annex II of eIDAS requires the device to guarantee that the signature creation data cannot practically be derived or copied, and that it stays under the sole control of the signatory. A key that can be read is not a QSCD key.
That has direct consequences for a modern deployment:
- A
.p12file in an environment variable fails. It can be copied by anyone with access to the deployment config, the process memory, or the CI logs. - A key in a secrets manager also fails. The manager's job is to hand you the key material, which is exactly the property a QSCD forbids.
- An ephemeral serverless function cannot hold a QSCD. It has no persistent secure element, and the runtime is shared infrastructure you do not control.
The two patterns that do work:
- A local HSM or smart card. The key is generated inside the device and never leaves it. The application sends a hash in and gets a signature out. This means a long-lived server, physical or virtual, with a hardware path to the device.
- Remote signing at a qualified trust service provider. The provider holds the key in its own certified HSM and exposes an API. Your code sends the document hash, authenticates, and receives the signature value. This is how most cloud-native teams meet the requirement without owning hardware, and it is the only option that composes with stateless application servers.
In the remote pattern, your application still never touches the private key. It holds an API credential to the provider, which is a very different risk profile: a leaked credential can be revoked and rate-limited, a leaked private key cannot be un-copied.
Portugal also runs the Chave Móvel Digital citizen identity scheme, which supports qualified signatures for natural persons. It is designed for individual signing flows rather than for machine-issued invoice volume, so for automated invoicing a qualified seal from a trust service provider is the more common fit. Check availability and terms with the provider rather than assuming a citizen scheme scales to server-side batch issuance.
What does this do to a PDF generation pipeline?
The signature freezes the bytes, so the biggest change is that a signed invoice can no longer be generated on demand. This is the part that breaks existing architectures, and it is worth stating plainly.
Many invoicing systems today render the PDF lazily. A customer clicks download, the server pulls the invoice row, fills an HTML template, renders it, and streams the result. Nothing is stored, because the document can always be rebuilt. That pattern dies the moment a signature is involved, for a mechanical reason: re-rendering produces different bytes. A different creation date in the document metadata, a different object ordering, a different font subset, and the hash no longer matches the one that was signed. The signature does not "still apply to the same invoice"; it applies to a byte sequence that no longer exists.
So the pipeline becomes ordered and one-way:
Four rules follow from that diagram.
Render once, at the moment the invoice is finalised. Not at download time. The render becomes an event in the invoice lifecycle, not a view concern.
Store the signed bytes, and treat them as the record of truth. Object storage with versioning off and deletion protection on. Your database row describes the invoice; the stored PDF is the invoice.
Serve the stored file byte for byte. No re-compression at the CDN, no PDF optimisation on the way out, no adding a watermark for the customer portal. Any of those invalidate the signature.
Correct by issuing a credit note, not by editing. A signed invoice with a typo cannot be fixed. This is normal accounting practice anyway, but systems that quietly allowed an invoice to be edited and re-rendered now need that path removed at the code level, not just in the UI.
There is a migration cost hiding here. If your current storage holds no PDFs because everything was rebuilt on demand, you are adding a storage tier, a retention policy, and a backup story to a system that previously had none of them. That work is larger than the signing integration, and it does not depend on the deadline holding.
Which libraries can do the signing?
The library layer is the least interesting part of the problem, because it does not produce the qualified part. Its job is to build a correct PAdES structure around a signature value that comes from somewhere else.
| Library | Language | PAdES support | Limitation |
|---|---|---|---|
| pyHanko | Python | B-B through B-LTA, PKCS#11 | Needs a PKCS#11 path or a custom signer for a remote TSP |
| DSS (Digital Signature Services) | Java | Full PAdES, EU-maintained | Java stack, heavier to operate |
| @signpdf/signpdf | Node.js | Placeholder plus PKCS#7 | Long-term levels need extra work |
| pdf-lib | Node.js | None | Draws images and fields, computes no signature |
Two honest caveats. First, none of these libraries make a signature qualified. They assemble the container; the qualified status comes entirely from the certificate and the QSCD behind the signature value. A pyHanko signature with a self-signed key is an advanced signature at best.
Second, most qualified trust service providers ship their own SDK or REST API, and integrating through it is usually less work than wiring a generic library to a remote signing interface. Check what your provider offers before choosing a library.
Where does an HTML to PDF API fit?
A rendering API produces the document; it does not produce the qualified signature. PDF4.dev renders an HTML invoice template into PDF bytes and returns them. Signing is a separate stage, run against those bytes by a service that holds a qualified certificate in a QSCD. Any vendor that claims an HTML to PDF call alone yields a Portuguese-compliant qualified signature is describing something the regulation does not allow.
The composition is straightforward. Render with a stable template, request the bytes, then hand them to the signing stage:
curl -X POST https://pdf4.dev/api/v1/render \
-H "Authorization: Bearer p4_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"template_id": "invoice-pt",
"data": {
"invoice_number": "FT 2027/000142",
"atcud": "JFV7DHR8-142",
"customer_nif": "501234567",
"total": "1.845,00 EUR"
},
"delivery": "url"
}'Fetch the bytes from that URL once, pass them to your qualified signing provider, and store what comes back. The stored file is what you deliver from then on. If you need to restrict what recipients can do with the delivered file, note that encryption also rewrites the document, so apply it before signing or not at all: the free Protect PdfTry it free tool is useful for testing that interaction on a sample invoice rather than on production output.
One template detail matters more than it looks: keep the rendering deterministic. Do not inject a "generated at" timestamp, a random document id, or remote assets that can change. You will re-render during testing and you want byte-identical output for identical input, otherwise debugging a broken signature becomes guesswork.
What to do between now and the deadline
Treat the 2027 date as the date in force and the architecture work as independent of it. The storage and lifecycle changes described above are the long pole, they take weeks rather than days in a system that never stored PDFs, and they deliver value regardless of whether the deadline moves again.
A reasonable order of work: separate rendering from delivery, add immutable storage for finalised invoices, make the render deterministic, then integrate a qualified trust service provider and pick a PAdES level with your accountant. The cryptography is the last step and the shortest one.
Related reading
- How to add a digital signature to a PDF: the code-level mechanics, PKCS#7, pyHanko and @signpdf.
- EU e-invoicing mandates: a developer guide: the wider European picture around Portugal.
- Germany B2B e-invoicing, six months out: a comparable 2027 deadline in another member state.
Free tools mentioned:
Start generating PDFs
Build PDF templates with a visual editor. Render them via API from any language in ~300ms.



