Product scope and limits
everything it doesn’t do, in one place.
Attestwire checks invoice data and creates invoice XML, and on the hosted API a Factur-X / ZUGFeRD PDF too. It can e-mail an invoice to one recipient on request; beyond that it does not send invoices, and it does not guarantee that a buyer will accept one. The tables say what is supported; the sections after them cover what people most often trip over, including every rule not yet implemented.
What you can check and create
| Capability | UBL 2.1 | CII D16B |
|---|---|---|
| Generate invoices | Yes | Yes |
| Generate credit notes | Yes | Yes |
| Read existing XML | Yes | Yes |
| Read a Factur-X or ZUGFeRD PDF | No PDF form exists | XML extracted; container checked |
| XRechnung profile | Yes | Yes |
| Peppol BIS 3 | Yes | Optional binding (library); API emits UBL |
| Factur-X EN 16931 payload | No | XML payload only |
| Finished PDF/A-3 | No | API, every plan (watermarked on Free) |
| Transmission | No | No |
Attestwire builds and checks the document data. Your access point or approved platform handles delivery. Uploaded XML gets a semantic preflight, not a receiver guarantee.
Other product boundaries
| Area | Supported | Not supported |
|---|---|---|
| Profiles | EN 16931 core, XRechnung in both syntaxes, and the Peppol BIS 3 base rules. | National Peppol overlays (NO-R-*, DK-R-*, SE-R-*), and the XRechnung Extension and CVD profiles. |
| Documents | Invoices and credit notes, generated and read, in both syntaxes. | The UBL debit-note document, and self-billing workflows. |
| Validation | A semantic preflight over your JSON input, or over a UBL/CII document parsed into that same model. | XSD or Schematron authority over the document at request time, and any statement about what a receiver will do with it. |
| Operations | Public status page, public rule pages, invoice payloads processed in memory and not stored. | Support SLA, SOC 2, ISO 27001, third-party penetration report. |
| Residency | US-operated. Cloudflare Workers runs the request at the point of presence nearest the caller, so a request from Germany is normally handled inside the EU. The MIT library runs wherever you run it and makes no network call. | A contractual EU-only processing commitment. Cloudflare chooses the location by proximity to the caller, so we cannot promise a jurisdiction. |
| Accounts | One API key per email address, issued instantly and shown once, stored as a SHA-256 hash; rotation from the key you hold. | A console, sign-in, SSO, roles, seats or an audit log. There is no account to log into; the API key is the only credential and the only identity. |
For procurement: there is no SOC 2, no ISO 27001 and no third-party penetration test, and there is no support SLA on any plan. There is also no console or SSO. See security and data handling for what is in place today.
Choose the rules and file format
A profile selects the rules to apply, such as XRechnung (the German add-on to the European standard, which makes optional fields mandatory; the technical name for such an add-on is a CIUS) or Peppol BIS (the rule set of the Peppol invoice network). A syntax is the XML file format: UBL or CII. The table shows which formats each profile can generate.
| Profile | Generated as | What it is |
|---|---|---|
xrechnung-ubl |
UBL 2.1 | The German add-on (XRechnung 3.0) written as UBL 2.1. This is the output KoSIT has judged, against the XRechnung 3.0.2 validator configuration. |
xrechnung-cii |
CII D16B | The German add-on written as CII. Also judged by KoSIT, against a CII Schematron. |
peppol-bis-3 |
UBL 2.1 and CII D16B | Peppol BIS Billing 3.0 base rules. UBL is mandatory for every receiver. CII is optional: OpenPeppol ships a CII schematron, and a receiver accepts CII only if it has registered for that in the SMP, the Peppol directory that records what each receiver accepts. So the library writes both and the hosted API emits Peppol as UBL. |
en16931 |
UBL 2.1 and CII D16B | The core standard, no national restrictions. The library writes it in either syntax; over the hosted API it comes back as UBL. |
facturx-en16931 |
CII D16B | The Factur-X EN 16931 CII payload, and only the payload. Not KoSIT-verified: it states the core EN 16931 specification identifier, which matches no XRechnung scenario, so the validator answers “no scenario matched” instead of a verdict. |
Validation covers all five profiles in both syntaxes. Generation is the narrower list above, because a profile with one binding has one binding in the standard.
The Peppol BIS 3 base rules cover Belgium and the Netherlands's Peppol-based flows at the base-rule level; national overlays (Norway, Denmark, Sweden and others) are not implemented.
PDF input and output
The library writes XML. It does not write a PDF.
Factur-X and ZUGFeRD place CII XML inside a PDF/A-3 container. The
library's generators, and the hosted API's JSON and XML responses,
return the CII XML only; package it into the PDF separately. The
hosted API builds that file for you, on every plan:
POST /v1/generate?format=pdf with
facturx-en16931 returns the Factur-X / ZUGFeRD PDF
(EN 16931 profile) — watermarked as a preview on the free plan, and
without the watermark on the Solo, Starter, and Scale plans.
The local library can read the XML attachment with
extractFacturX(bytes), and the hosted API reads a Factur-X
or ZUGFeRD PDF sent as application/pdf, on every plan. Both
judge the XML attached to it, and both now check the PDF's container
too — the attachment (its name, /AFRelationship and MIME
type) and the XMP metadata — as AW-PDF-* findings, none of
them fatal.
Neither checks PDF/A conformance itself, or whether the drawn page agrees with the XML. The browser checker accepts XML, not PDF files.
Generated XML is not a Factur-X document and it is not a ZUGFeRD document until the XML has been packaged into the required PDF/A-3 container.
Two edge cases to know before you build
Two more, the project reference on a UBL credit note and the XPaths on credit-note findings, are in the list of rules not implemented below.
-
The generic
en16931profile needs syntax awareness. It runs the core rules and nothing national, and it writes in either binding, so the code lists and identifier schemes your receiver expects follow the syntax you ask for, not the profile. Name the target profile when you know it. - Size limits reject large embedded attachments. The hosted API refuses any request body over 1 MB, and the XML reader underneath it refuses a document over 8,000,000 characters. Base64 spends four characters per three bytes, so an embedded PDF of roughly 750 kB fills the hosted request body on its own. Attach large files outside the document.
Rules that are not implemented
Every rule of EN 16931, the German XRechnung add-on and Peppol BIS 3 that the input model can express is implemented. What is left out is the list below, and it is the complete list.
- Factur-X and ZUGFeRD as a PDF. Factur-X and ZUGFeRD are CII XML inside a PDF/A-3 container. As of 0.7.0 the library reads that container — extractFacturX(bytes) returns the embedded XML from a Factur-X or ZUGFeRD PDF — but it still does not build one. It writes the CII XML only: it does not produce the PDF/A-3, does not attach the XML under the required file name (factur-x.xml, or xrechnung.xml for the XRECHNUNG reference profile), and does not set the /AFRelationship value Germany requires. So generated output is a CII XML file rather than a finished Factur-X or ZUGFeRD PDF. Take the XML to a PDF/A-3 library to make the file. The hosted API is the exception: POST /v1/generate?format=pdf returns a Factur-X / ZUGFeRD PDF (EN 16931 profile) that it builds itself, on every plan — watermarked as a preview on the free plan, without the watermark on the paid plans.
- Validating the XML itself. The library reads a UBL or CII file into the input model, then checks the model. That is a pre-flight over the parsed input, not a schematron over the document. Rules that constrain the XML rather than the input — BR-DE-13 and BR-DE-21 on BT-24 — still do not run. A document we accept can still be rejected by the reference validator.
- Debit notes. UBL has a DebitNote document and EN 16931 has no binding for it, so there is nothing to implement against. Credit notes are a different answer and used to be on this list: since 0.5.0 they are generated, read and validated in both syntaxes, and the two rows below are what is left of that gap rather than the gap itself.
- The project reference on a UBL credit note. cac:ProjectReference is not in UBL-CreditNote-2.1.xsd at all, so no conformant UBL credit note can carry BT-11 by any means. The gap is in the UBL format itself; the CII format keeps the reference. Supplying one on a UBL credit note raises a finding naming what will be missing, rather than dropping the field in silence. The payment due date (BT-9) has the same problem but a way out: it moves into the payment instructions group.
- XPaths on credit-note findings. Every finding carries an xpath, and it is a fixed string per rule. Most of them still read /ubl:Invoice/… on a credit note. The rules that exist because the document is a credit note name /ubl:CreditNote correctly; the rest do not. An xpath here is documentation of where a term lives, not a resolved location in your document.
- Peppol rules inside the XRechnung schematron. KoSIT’s XRechnung schematron runs a few PEPPOL-EN16931 rules for both syntaxes, PEPPOL-EN16931-R040 among them. This build runs its Peppol rules only when the profile is peppol-bis-3. So R040 does not run here for an XRechnung invoice, even though KoSIT runs it. This is not new; the 2026-08-11 KoSIT run is what named it.
- Rules the generator controls. A handful of rules constrain XML this library writes from the profile rather than from anything you send, so there is no input that can fail them. They belong to a document-validation entry point, not to an input pre-flight.
- Four rules the regulator does not test either. BR-CO-05 to BR-CO-08 require a reason code and a reason text to mean the same thing, which has no mechanical test; the reference schematron binds all four to true(). BR-CO-25 is in neither schematron, so implementing it would reject documents the authority accepts.
- VAT category B, and the Extension and CVD profiles. Split payment (Italy) has no rule family to implement, so a line carrying it is refused rather than passed silently. BR-DEX-* and BR-DE-CVD-* apply to customization ids this build does not emit.
- National Peppol rule sets. NO-R-*, DK-R-*, SE-R-* and the rest are country overlays on top of the BIS rules, each a project of its own. A document this library accepts is checked against the core, XRechnung and Peppol BIS sets, not against a receiving country’s extra requirements.
Delivery is separate
Attestwire is not a Peppol access point, a French PDP or a KSeF connector. An access point is the service that puts an invoice onto the Peppol network; a PDP is one of the accredited platforms that will carry e-invoices in France; KSeF is Poland's national invoicing system.
Attestwire builds and checks the document, and can e-mail it to one recipient on request — an accepted channel for German B2B, not a substitute for any of the three. Your access point or approved platform delivers it everywhere else.
What a passing result means
valid: true means the implemented checks found no fatal
error in the data you sent. It does not mean a tax authority, a portal,
an access point or your customer will accept the document, and it is
not tax or legal advice.
The terms say the same thing, in
clause three.
Recorded validator testing
KoSIT, the German government’s validator, accepts all eleven sample invoices this library generates. One of them draws a warning from a European rule that KoSIT itself has marked as broken and replaced; it passes the replacement. None draws an error. The run is about those documents only, it is not a parity suite, and the full record, with its commands and scope, is on the KoSIT conformance record.
Validator 1.6.3, XRechnung 3.0.2 configuration (build of 31 August 2026), CEN CII schematron 1.3.16, XRechnung CII schematron 2.6.0; recorded against engine 0.10.0. The warning is CII-SR-475 on the extended CII fixture, a rule that miscounts attachments when an invoice has more than one (CEN issue 508). KoSIT’s configuration lowers it to information and checks BR-TMP-4 instead, which passes.
Blocked by something on this page? Say so at hello@attestwire.com before you integrate. Pricing · About Attestwire · Source.
Last updated . If this page changes materially we will say so here rather than silently swapping it.