Work in progress
This library will be used to read, write and verify electronic invoices (XML) which conform to the EN 16931 standard.
go get github.com/speedata/einvoice
invoice, err := einvoice.ParseXMLFile(filename)
if err != nil {
...
}
// now invoice contains all the information from the XML file
// check for validation violations
err = invoice.Validate()
if err != nil {
var valErr *einvoice.ValidationError
if errors.As(err, &valErr) {
for _, v := range valErr.Violations() {
fmt.Printf("Error: %s - %s\n", v.Rule.Code, v.Text)
}
for _, w := range valErr.Warnings() {
fmt.Printf("Warning: %s - %s\n", w.Rule.Code, w.Text)
}
}
} else {
// Validation passed - check for recommendations
for _, w := range invoice.Warnings() {
fmt.Printf("Recommendation: %s - %s\n", w.Rule.Code, w.Text)
}
}Building and validating an invoice programmatically:
import "errors"
func buildInvoice() error {
inv := &einvoice.Invoice{
InvoiceNumber: "INV-001",
// ... set all required fields
}
// Validate before writing
if err := inv.Validate(); err != nil {
var valErr *einvoice.ValidationError
if errors.As(err, &valErr) {
for _, v := range valErr.Violations() {
fmt.Printf("Rule %s: %s\n", v.Rule, v.Text)
}
}
return err
}
return inv.Write(os.Stdout)
}Round-trip: parsing and writing back:
func dothings() error {
inv, err := einvoice.ParseXMLFile("...")
if err != nil {
return err
}
// Write back in the same format (CII or UBL)
return inv.Write(os.Stdout)
}The Validate() method automatically detects and applies the appropriate validation rules:
- EN 16931 Core Rules: Always validated for all invoices
- PEPPOL BIS Billing 3.0: Auto-detected based on specification identifier (BT-24)
- Country-Specific Rules: Auto-detected based on seller country (future: DK, IT, NL, NO, SE)
Example of a PEPPOL invoice being automatically validated:
inv := &einvoice.Invoice{
GuidelineSpecifiedDocumentContextParameter: "urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0",
BPSpecifiedDocumentContextParameter: "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0",
// ... other fields
}
// Automatically validates both EN 16931 AND PEPPOL rules
if err := inv.Validate(); err != nil {
// Handle validation errors
}No need to call separate validation methods - Validate() handles everything automatically!
The validation framework distinguishes between errors (hard requirements) and warnings (recommendations):
- Errors: Violations of "must" requirements cause
Validate()to return an error - Warnings: Violations of "should" recommendations don't fail validation but are reported
err := invoice.Validate()
if err == nil {
// Validation passed - but check for recommendations
if invoice.HasWarnings() {
for _, w := range invoice.Warnings() {
fmt.Printf("Recommendation: %s - %s\n", w.Rule.Code, w.Text)
}
}
}The warning infrastructure is available for future "should" (German: "soll") rules from various CIUS specifications.
There is a dedicated example in the documentation.
A CLI tool is available for validating invoices from the command line.
go install github.com/speedata/einvoice/cmd/einvoice@latestValidate an invoice and display violations in human-readable format:
einvoice validate invoice.xmlOutput validation results as JSON (useful for automation and CI/CD):
einvoice validate --format json invoice.xml0- Invoice is valid (no violations)1- Error occurred (file not found, parse error, etc.)2- Invoice has validation violations
These exit codes make it easy to integrate the validator into shell scripts and CI/CD pipelines:
if einvoice validate invoice.xml; then
echo "Invoice is valid!"
else
echo "Validation failed"
fi- Reading and writing of EN 16931 invoices in both formats:
- ZUGFeRD/Factur-X (CII format)
- UBL 2.1 (Invoice and CreditNote)
- Intelligent validation with auto-detection:
- EN 16931 Core Rules: BR-1 to BR-65, BR-CO-, BR-DEC-
- VAT Category Rules: BR-S-, BR-AE-, BR-E-, BR-Z-, BR-G-, BR-IC-, BR-IG-, BR-IP-, BR-O-*
- PEPPOL BIS Billing 3.0: Auto-detected and validated (PEPPOL-EN16931-R*)
- Single
Validate()method handles all rule sets automatically
- XML output for all ZUGFeRD profiles (Minimum, BasicWL, Basic, EN16931, Extended, XRechnung)
- UBL 2.1 Invoice and CreditNote output with full EN 16931 compliance
- Profile detection based on specification identifier URN (BT-24)
- Format auto-detection when parsing (automatically recognizes CII or UBL)
- Round-trip support: parse and write back in the same format
We welcome contributions! Please see CONTRIBUTING.md for:
- Development setup and prerequisites
- Running tests and checking coverage
- Code style and conventions
- Pull request process
- How to work with test fixtures
Test fixtures are organized by profile and format in the testdata/ directory. See testdata/README.md for:
- Directory structure and organization
- Fixture sources and provenance (from official EN 16931 and PEPPOL test suites)
- How to add new fixtures
- Usage patterns in tests