Validator API
Validate e-invoices against official KoSIT schemas and Schematron rules. Get detailed error messages with correction suggestions.
/api/v1/invoice/{countryCode}/validateValidation only works with a valid bearer key. Without one the endpoint answers 401.
Check before you send
Catch format errors before the invoice reaches the recipient — with error message and correction hint.
KoSIT-compliant
Official Schematron rules from KoSIT (Coordination Office for IT Standards)
37 Countries
Support for AE, AT, AU, BE, BG, CH, CY, CZ, DE, DK, EE, ES, FI, FR, GB, GR, HR, HU, IE, IS, IT, JP, LI, LT, LU, LV, MT, NL, NO, NZ, OM, PL, PT, RO, SE, SI, SK
All Formats
XRechnung, ZUGFeRD, Factur-X, Peppol UBL and national formats (FatturaPA, ebInterface, Facturae, ISDOC, NAV, myDATA, KSeF FA(3), eFactura/CIUS-RO, CIUS-PT, QR-Bill) are supported — the full table is further down.
Example
1curl -X POST 'https://service.invoice-api.xhub.io/api/v1/invoice/de/validate' \2 -H 'Authorization: Bearer sk_test_xxx' \3 -H 'Content-Type: application/json' \4 -d '{5 "invoice": {6 "invoiceNumber": "RE-2026-001",7 "type": "invoice",8 "issueDate": "2026-01-15",9 "dueDate": "2026-02-15",10 "currency": "EUR",11 "seller": {12 "name": "Meine Firma GmbH",13 "street": "Musterstraße 1",14 "city": "Berlin",15 "postalCode": "10115",16 "countryCode": "DE",17 "vatId": "DE123456789"18 },19 "buyer": {20 "name": "Kunde AG",21 "street": "Kundenweg 42",22 "city": "München",23 "postalCode": "80331",24 "countryCode": "DE",25 "vatId": "DE987654321"26 },27 "items": [{28 "position": 1,29 "description": "Beratung",30 "quantity": 10,31 "unit": "HUR",32 "unitPrice": 150.00,33 "taxRate": 19,34 "netAmount": 1500.00,35 "taxAmount": 285.00,36 "grossAmount": 1785.0037 }],38 "subtotal": 1500.00,39 "total": 1785.00,40 "taxSummary": [{ "taxRate": 19, "netAmount": 1500.00, "taxAmount": 285.00 }],41 "paymentTerms": { "dueDays": 30 }42 }43 }'Validate one format
/api/v1/invoice/{countryCode}/{format}/validateNext to the country-wide route there is one route per format. It generates the invoice in exactly that format and runs the result through that format's XSD and Schematron — instead of through those of every format the country has.
Country-wide route
/api/v1/invoice/{countryCode}/validateChecks every format the country has, plus the country's own business rules. For DE the invoice above yields eleven entries in results[] — XRechnung and ten ZUGFeRD profiles — and the codes DE_REF_002 and DE_SELLER_CONTACT_001 in errors[] (measured on 2026-09-15).
Format route
/api/v1/invoice/{countryCode}/{format}/validateChecks exactly one format. For ZUGFeRD and Factur-X every profile is generated and checked, which is why results[] carries several entries there. The country's business rules do not run here: valid refers to the generated XML alone.
format path parameter
The spec knows these values, always lowercase:
ebinterfaceebInterfacefacturaeFacturaefacturxFactur-XfatturapaFatturaPAhr-fiskHR-FISKisdocISDOCksefKSeFmydatamyDATAnavNAVpdfPDFpeppol-ublPeppol UBLqr-billQR-BillublUBLxrechnungXRechnungzugferdZUGFeRDWhich of them a country actually carries as a validatable XML format depends on the country — the formats endpoint returns the list per country. A value the country does not carry is rejected with 400: /de/pdf/validate answers "Format 'pdf' is not a validatable XML format for country DE" (measured on 2026-09-15).
Request
1curl -X POST 'https://service.invoice-api.xhub.io/api/v1/invoice/de/zugferd/validate' \2 -H 'Authorization: Bearer sk_test_xxx' \3 -H 'Content-Type: application/json' \4 -d '{5 "invoice": {6 "invoiceNumber": "RE-2026-001",7 "type": "invoice",8 "issueDate": "2026-01-15",9 "dueDate": "2026-02-15",10 "currency": "EUR",11 "seller": {12 "name": "Meine Firma GmbH",13 "street": "Musterstraße 1",14 "city": "Berlin",15 "postalCode": "10115",16 "countryCode": "DE",17 "vatId": "DE123456789"18 },19 "buyer": {20 "name": "Kunde AG",21 "street": "Kundenweg 42",22 "city": "München",23 "postalCode": "80331",24 "countryCode": "DE",25 "vatId": "DE987654321"26 },27 "items": [{28 "position": 1,29 "description": "Beratung",30 "quantity": 10,31 "unit": "HUR",32 "unitPrice": 150.00,33 "taxRate": 19,34 "netAmount": 1500.00,35 "taxAmount": 285.00,36 "grossAmount": 1785.0037 }],38 "subtotal": 1500.00,39 "total": 1785.00,40 "taxSummary": [{ "taxRate": 19, "netAmount": 1500.00, "taxAmount": 285.00 }],41 "paymentTerms": { "dueDays": 30 }42 }43 }'Response
The same invoice as above, sent to /de/zugferd/validate — the service's answer of 2026-09-15, unchanged:
1{2 "valid": true,3 "results": [4 { "format": "zugferd-2.4-minimum", "valid": true, "errors": [] },5 { "format": "zugferd-2.4-en16931", "valid": true, "errors": [] },6 { "format": "zugferd-2.4-basic", "valid": true, "errors": [] },7 { "format": "zugferd-2.4-basic-wl", "valid": true, "errors": [] },8 { "format": "zugferd-2.4-extended", "valid": true, "errors": [] },9 { "format": "zugferd-2.5-minimum", "valid": true, "errors": [] },10 { "format": "zugferd-2.5-en16931", "valid": true, "errors": [] },11 { "format": "zugferd-2.5-basic", "valid": true, "errors": [] },12 { "format": "zugferd-2.5-basic-wl", "valid": true, "errors": [] },13 { "format": "zugferd-2.5-extended", "valid": true, "errors": [] }14 ]15}Sent to /de/xrechnung/validate the same invoice yields valid: false, one entry in results[] (xrechnung-3.0.2-ubl) and the rule codes PEPPOL-EN16931-R020, BR-DE-1, BR-DE-6, BR-DE-7 and BR-DE-15. Each entry there carries location (XPath) and severity; the same findings also appear flat in errors[].
Auth and quota as on the country-wide route: a bearer key is required (401 without it), and the call is bound to the key's monthly quota — once that is exhausted this route answers 429 as well. Plan it like a generation call: the check generates the document internally.
Supported Countries
The country code is specified as part of the URL: /api/v1/invoice/{countryCode}/validate
DEGermany
ATAustria
CHSwitzerland
FRFrance
ITItaly
ESSpain
NLNetherlands
BEBelgium
PLPoland
PTPortugal
AEUnited Arab Emirates
AUAustralia
BGBulgaria
CYCyprus
CZCzech Republic
DKDenmark
EEEstonia
FIFinland
GBUnited Kingdom
GRGreece
HRCroatia
HUHungary
IEIreland
ISIceland
JPJapan
LILiechtenstein
LTLithuania
LULuxembourg
LVLatvia
MTMalta
NONorway
NZNew Zealand
OMOman
RORomania
SESweden
SISlovenia
SKSlovakia
= Available
Germany
/api/v1/invoice/de/validateAustria
/api/v1/invoice/at/validateFrance
/api/v1/invoice/fr/validateItaly
/api/v1/invoice/it/validateSwitzerland
/api/v1/invoice/ch/validateSpain
/api/v1/invoice/es/validateRequest Parameters
Path Parameter
| Parameter | Type | Required | Description |
|---|---|---|---|
countryCode | string | ISO 3166-1 alpha-2 country code. Available (37): AE, AT, AU, BE, BG, CH, CY, CZ, DE, DK, EE, ES, FI, FR, GB, GR, HR, HU, IE, IS, IT, JP, LI, LT, LU, LV, MT, NL, NO, NZ, OM, PL, PT, RO, SE, SI, SK. |
Headers & Body
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | header | Bearer token with sk_test_* or sk_live_* API key | |
Content-Type | header | application/json | |
invoice | object (body) | The invoice object to validate (JSON). The endpoint accepts a JSON body with an invoice field only — no raw XML, no file upload. |
Authentication
Use your API key in the Authorization header: for test environment or for production.Bearer sk_test_... / Bearer sk_live_...
Response
Valid Invoice
200 OK1{2 "valid": true,3 "errors": [],4 "warnings": []5}Invalid Invoice
200 OK1{2 "valid": false,3 "errors": [4 {5 "code": "BR-DE-1",6 "message": "Eine Rechnung (INVOICE) muss Angaben zu "PAYMENT INSTRUCTIONS" (BG-16) enthalten.",7 "field": "/Invoice/cac:PaymentMeans"8 },9 {10 "code": "BR-DE-15",11 "message": "Das Element "Buyer reference" (BT-10) muss übermittelt werden.",12 "field": "/Invoice/cbc:BuyerReference"13 }14 ],15 "warnings": [16 {17 "code": "MISSING_OPTIONAL",18 "message": "Delivery date is recommended",19 "field": "deliveryDate"20 }21 ]22}Error Responses
1{2 "error": "Bad Request",3 "message": "Invoice data is required"4}1{2 "error": "UNAUTHORIZED",3 "message": "Invalid or missing API key"4}1{2 "error": "INTERNAL_ERROR",3 "message": "An unexpected error occurred"4}Response Fields
valid
true / false
errors
Array of errors. Each error contains code, message and optionally field.
warnings
Array of warnings. Same schema as errors, but not critical issues.
Schema for Errors/Warnings
| Field | Type | Description |
|---|---|---|
code | string | Error code (e.g. BR-DE-01, BR-16) |
message | string | Human-readable error description |
field | string (optional) | XPath or field name where the error occurred |
Supported Formats
| Format | Schema | Validierung |
|---|---|---|
| XRechnung 3.0.2 | EN16931 CII/UBL | KoSIT 3.0.2 Schematron |
| XRechnung 3.0 | EN16931 CII/UBL | KoSIT 3.0 Schematron |
| ZUGFeRD 2.5 | EN16931 CII | EN16931 Schematron |
| ZUGFeRD 2.4 | EN16931 CII | EN16931 Schematron |
| ZUGFeRD 2.3 | EN16931 CII | EN16931 Schematron |
| Factur-X 1.09 | EN16931 CII | EN16931 Schematron |
| Factur-X 1.08 | EN16931 CII | EN16931 Schematron |
| Factur-X 1.0 | EN16931 CII | EN16931 Schematron |
| UBL (Peppol BIS 3.0) | EN16931 UBL | Peppol BIS 3.0 / EN16931 |
| ebInterface | ebInterface XSD (AT) | ebInterface |
| FatturaPA 1.2.3 | FatturaPA XSD (IT) | SDI-Schema |
| Facturae | Facturae XSD (ES) | Facturae XSD |
| ISDOC | ISDOC XSD (CZ) | ISDOC XSD |
| NAV | NAV XSD (HU) | NAV-Online XSD |
| myDATA | myDATA XSD (GR) | myDATA XSD |
| KSeF FA(3) | KSeF UBL-Slot (PL) | KSeF FA(3) XSD |
| eFactura (CIUS-RO) | EN16931 UBL | CIUS-RO |
| CIUS-PT | EN16931 UBL | CIUS-PT |
| QR-Bill | Swiss QR-Bill (CH/LI) | QR-Bill Spezifikation |
Common Validation Errors
BR-DE-1Payment instructions missing: an invoice must contain payment information (BG-16)
Solution: Set paymentMethods (e.g. bank_transfer) together with seller.bankAccount including the IBAN
BR-DE-15Buyer reference missing: the element Buyer reference (BT-10) must be provided
Solution: Set countrySpecific.buyerReference — for public-sector buyers the Leitweg ID in countrySpecific.leitwegId
BR-DE-17Invalid invoice type: the invoice type code (BT-3) must be 326, 380, 384, 389, 381, 875, 876 or 877
Solution: Set invoice.type to a permitted value (invoice = 380); proforma is not allowed in XRechnung
BR-16No invoice line: an invoice must contain at least one line (BG-25)
Solution: Add at least one entry to items
BR-CO-10Sum of line item net amounts does not equal invoice net
Solution: Check the sum of all items[].quantity * items[].unitPrice
Full error list: Error Handling Documentation
On both validate routes the number of invoice line items is capped per plan, exactly as when generating — above the cap the API answers with HTTP 400 and TOO_MANY_LINE_ITEMS: Limits in the Creator API
Validation and your quota
The validation call itself is not metered against your monthly quota — but it is bound to it: once the quota is exhausted, validation answers 429 as well. Keep that in mind when validating in CI/CD pipelines or automated tests.
Validation in Playground
The Playground lets you try validation without an API key of your own — the request runs on our key there and is rate-limited per IP. The endpoint itself always requires a bearer key.
Go to Playground →