CII Validation API Reference
Technical reference for validating standalone UN/CEFACT Cross Industry Invoice (CII) XML. The endpoint runs the CII XSD, then the business rules matching the profile declared in BT-24: the EN 16931 Schematron for core documents, the official Factur-X / ZUGFeRD per-profile rules for MINIMUM through EXTENDED, and the KoSIT rules for XRechnung CII. Findings are returned as structured JSON.
https://api.invoicexml.com/v1/validate/cii
Code Example
curl -X POST https://api.invoicexml.com/v1/validate/cii \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "[email protected]" \ -F "validationLanguage=en"
The invoice profile and version are detected automatically from the uploaded file, so you never need to pass them. The detected values are returned in the response.
French mandate rules on demand
To check the file against the French CTC mandate as well, add the optional
rules form field with br-fr. The
BR-FR Flux 2 rules, the same rule set the Plateformes Agréées and the PPF apply to every
domestic French invoice, then run on top of the rule set the document's declared profile selects:
curl -X POST https://api.invoicexml.com/v1/validate/cii \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "[email protected]" \ -F "rules=br-fr"
The base verdict is unchanged: profile detection, data.profile and
data.customizationId all work exactly as without the field, and the
mandate findings appear in the same errors array with rule ids
starting with BR-FR. Documents declaring the MINIMUM or BASIC WL profile are rejected with a 400: the mandate reads those header-only subsets as booking aids, not invoices. A document declaring the EXTENDED-CTC-FR
profile already runs these rules by default, so the field adds nothing there.
Findings in German or French
Every finding carries a plain-language message you can show to your users. It is
written in English unless the optional validationLanguage form field asks for
German (de) or French (fr):
curl -X POST https://api.invoicexml.com/v1/validate/cii \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "[email protected]" \ -F "validationLanguage=de"
The verdict is unchanged, and so are rule, layer,
btCodes, fields and raw,
so keep matching on the rule id and field paths, never on the message text. Rules without a curated German or
French wording, such as the CII-SR and UBL-SR syntax rules, keep the rule set's English message.
Localized error messages
has the details.
Try it out online, no coding required
Upload an invoice and get a full compliance report instantly, right in your browser.
Request
| Parameter | Type | Description |
|---|---|---|
| file * | binary | The invoice file to validate. Accepted format: standalone CII XML document. PDFs are not accepted here; upload hybrid files to POST /v1/validate/facturx or /v1/validate/zugferd. |
| rules | string | Optional. Extra national rule sets to check ON TOP of the rule set the document's declared profile selects. br-fr runs the BR-FR Flux 2 rules of the French CTC mandate, the same set the Plateformes Agréées and the PPF apply to every domestic invoice. Violations are reported as regular findings whose rule ids start with BR-FR; an unknown value is rejected with a 400 rather than skipped. |
| validationLanguage | string | Optional. Language of the finding messages: en (default), de or fr, in any letter case. The message of each entry in errors and warnings and the name of each report row change; rule, btCodes, fields, code and raw stay the same. Any other value, regional tags such as de-DE included, is rejected with a 400 (errorCode 4002). See localized error messages. |
Content-Type: multipart/form-data
That is the whole request. The syntax and the conformance profile (Peppol BIS, XRechnung, NLCIUS, PINT,
or the Factur-X/ZUGFeRD profile ladder) are detected automatically from the document's specification
identifier (BT-24), the matching rule set is applied, and the response reports what was validated against
in data.profile and data.customizationId.
Headers
| Header | Value |
|---|---|
| Authorization * | Bearer YOUR_API_KEY |
| Content-Type | multipart/form-data |
Response
200 Valid invoice
The invoice passed every check. valid is true and errors is empty.
{
"valid": true,
"detail": "Your invoice is cii compliant and meets the EN 16931 specifications.",
"data": {
"schemaValid": true,
"schematronValid": true,
"conformanceLevel": "EN16931",
"profile": "en16931",
"customizationId": "urn:cen.eu:en16931:2017"
},
"errors": [],
"warnings": [],
"report": [
{ "code": "BT-1", "name": "Invoice number", "section": "header", "path": "invoiceNumber", "value": "INV-2026-001", "isValid": true, "errors": [], "warnings": [] },
{ "code": "BT-2", "name": "Invoice issue date", "section": "header", "path": "issueDate", "value": "2026-05-19", "isValid": true, "errors": [], "warnings": [] }
// ... one row per EN 16931 Business Term. See the Validation Report section below.
]
}
200 Invalid invoice
Validation still returns HTTP 200. valid is false and the findings are in the errors array.
{
"valid": false,
"detail": "Validation failed with 3 error(s)",
"data": {
"schemaValid": true,
"schematronValid": false,
"conformanceLevel": "EN16931",
"profile": "en16931",
"customizationId": "urn:cen.eu:en16931:2017"
},
"errors": [
{
"rule": "BR-01",
"layer": "en16931",
"line": null,
"message": "Enter the specification identifier, which names the standard the invoice follows, for example urn:cen.eu:en16931:2017.",
"btCodes": ["BT-24"],
"fields": ["specificationId"],
"raw": "[BR-01] EN16931: An invoice shall have a specification identifier. (at /*:CrossIndustryInvoice)"
},
{
"rule": "BR-06",
"layer": "en16931",
"line": null,
"message": "Enter the seller name.",
"btCodes": ["BT-27"],
"fields": ["seller.name"],
"raw": "[BR-06] EN16931: An invoice shall contain the seller name. (at /*:CrossIndustryInvoice/*:SupplyChainTradeTransaction/*:ApplicableHeaderTradeAgreement/*:SellerTradeParty)"
},
{
"rule": "BR-24",
"layer": "en16931",
"line": 2,
"message": "Enter the net amount of this line.",
"btCodes": ["BT-131"],
"fields": ["lines[1].lineNetAmount"],
"raw": "[BR-24] EN16931: Each Invoice line shall have an Invoice line net amount. (at /*:CrossIndustryInvoice/*:SupplyChainTradeTransaction/*:IncludedSupplyChainTradeLineItem[2])"
}
],
"warnings": [
{
"rule": "BR-CL-01",
"layer": "en16931",
"line": null,
"message": "Choose an invoice type code from the UNTDID 1001 list, for example 380 (invoice) or 381 (credit note).",
"btCodes": ["BT-3"],
"fields": ["typeCode"],
"raw": "[BR-CL-01] EN16931-codelist: The document type code MUST be coded according to UNTDID 1001. (at /*:CrossIndustryInvoice/*:ExchangedDocument/*:TypeCode)"
}
],
"report": [
// ... one row per EN 16931 Business Term. See the Validation Report section below.
{ "code": "BT-27", "name": "Seller name", "section": "seller", "path": "seller.name", "value": null, "isValid": false, "errors": [{ "rule": "BR-06", "message": "Enter the seller name." }], "warnings": [] }
]
}
Error Reference
When an invoice fails validation, the top-level errors array contains one "finding" object per violated business rule. The warnings array uses the same finding shape for non-blocking advisory issues that do not cause valid to become false. On a valid invoice errors is an empty array, while warnings may still contain entries.
Each finding object carries both a friendly, user-facing message and the verbatim technical raw validator output. Each object contains:
| Field | Type | Description |
|---|---|---|
| rule | string | The business rule identifier (e.g. BR-01, BR-DE-15). |
| layer | string | null | The validation layer that produced the finding: xsd (XML schema), en16931 (EN 16931 core business rules), or cius (profile overlay rules such as Peppol BIS or BR-DE). The PDF embedding findings (PDF-EMBED, PDF-EMBED-SYNTAX) report upload problems rather than rule violations, so their layer is null. |
| line | int | null | The 1-based invoice line item number the error relates to, or null when the error applies to the document level. The line number is not repeated inside message, so compose any "Line 2:" display prefix from this field. |
| message | string | A plain-language explanation of the violation, suitable for displaying directly to end users. Written in English unless validationLanguage asks for German or French. |
| btCodes | string[] | The EN 16931 Business Term / Business Group codes the rule references (e.g. ["BT-27"]). Empty when the rule maps to no specific term. |
| fields | string[] | Dotted JSON paths into the invoice document that the error applies to (e.g. ["seller.name"], ["lines[1].lineNetAmount"]). Derived from btCodes; line-scoped paths carry a zero-based lines[N] index. Empty when no field could be resolved. |
| raw | string | The verbatim technical message from the validator, including the rule id, layer and XPath location. |
The fields array is intended for client UIs: each path matches the request body structure, so a front-end form can map a validation error straight onto the input that produced it. Highlight that input, attach message beside it, and the user can correct the exact field without reading the raw rule text. Line-scoped paths use a zero-based index (lines[1] is the second line item) to match JavaScript array indexing.
| Status | Meaning | Action |
|---|---|---|
| 200 | Validation completed. Check valid to determine compliance. |
If valid is false, inspect the errors array. |
| 401 | Missing or invalid API key. | Check the Authorization header. |
| 422 | File is not a valid PDF or XML document. | Ensure you are uploading a supported file format. |
Validation Report
Every response, whether the invoice is valid or not, includes a top-level report array. It contains one row per EN 16931 Business Term present on the parsed invoice, pairing each term with its current value and a pass/fail flag. This gives a complete, field-by-field picture of the document, not just the rules that failed, which is useful for rendering a compliance table or a side-by-side review UI. The snippets above show report truncated to a couple of rows to avoid repeating the full structure.
Each row in the array is an object with the following fields:
| Field | Type | Description |
|---|---|---|
| code | string | The EN 16931 Business Term code (e.g. BT-1). |
| name | string | The human-readable name of the Business Term, in English unless validationLanguage asks for German or French. Key on code, which is the same in every language. |
| section | string | Logical grouping for display: header, seller, buyer, lines, payment, totals, or tax. |
| path | string | Dotted JSON path into the invoice document (e.g. lines[0].priceDetails.netPrice). Same path scheme as errors[].fields. |
| value | string | null | The current value of the term as a string, or null when the field is absent. |
| isValid | boolean | true when this row has no errors, otherwise false. |
| errors | object[] | Every error finding referencing this Business Term as { "rule", "message" } objects; empty when none. The rule id is stable across releases, so it can key documentation links; the message follows validationLanguage. |
| warnings | object[] | Every warning finding referencing this Business Term, in the same { "rule", "message" } shape; empty when none. |
A single report row looks like this:
{
"code": "BT-1",
"name": "Invoice number",
"section": "header",
"path": "invoiceNumber",
"value": "INV-2026-001",
"isValid": true,
"errors": [],
"warnings": []
}
Prefer a printable PDF report?
The PDF report variant of this endpoint (/v1/validate/cii/report) runs the identical validation and returns a downloadable PDF compliance report, with the verdict in the X-Invoice-Valid response header.
Useful resources
Companion material for integrating against the API.