Use caseCustom softwareDocument AI

An e-invoice layer that lets an old ERP issue XRechnung and ZUGFeRD before 2027

From 1 January 2027, German firms above EUR 800,000 turnover must issue e-invoices. A converter layer makes an old ERP produce valid XRechnung and ZUGFeRD.

A blueprint, not a client story. The business described is illustrative; the architecture, integrations and trade-offs are real, and this is how I would build it. By Ergini, .

The short version

Custom software for German companies whose ERP or billing system cannot produce e-invoices in time for the 2027 mandate. It reads invoice data from the database, an export or, as a last resort, the print output, maps it to the EN 16931 model, generates XRechnung or a ZUGFeRD PDF, validates each file with the KoSIT validator, then sends and archives it. Mostly deterministic code: a model helps during setup, and a person handles every stopped invoice.

Best for
German manufacturers and agencies above EUR 800,000 turnover whose billing runs on an old ERP, an Access database or custom software with no e-invoice export.
Connects to
The existing ERP or billing system, KoSIT validator, Email (Outlook or plain SMTP), Peppol access point, DATEV
The AI does
Proposes field and unit mappings during setup, reads print PDFs when no data export exists, and finds order numbers buried in free-text remarks.
People do
Confirm the mapping once, fix the master data the validator rejects, agree formats with customers, and release every stopped invoice.
Built as
Custom Software Development, quoted per scope

Less than four months, and an ERP from another decade

Say you make machine parts with a dozen people and about EUR 1.2 million turnover, billing from an industry ERP installed in 2009. The vendor's e-invoicing module needs an upgrade your customizations will not survive, or the vendor has stopped answering. Every invoice leaves as a PDF from the print routine. An agency billing from a homegrown timesheet tool is in the same position.

From 1 January 2027, a German business whose turnover in the previous year exceeded EUR 800,000 must issue e-invoices for domestic B2B sales, and from 1 January 2028 every business must. An e-invoice means a structured format that follows EN 16931, which in practice means XRechnung or ZUGFeRD. A PDF, however tidy, no longer meets the requirement.

Only domestic business invoices are covered. Invoices to consumers, small invoices up to EUR 250 and invoices to customers abroad can stay as they are for now, although the EU's ViDA package brings e-invoicing to cross-border B2B trade in 2030. Receiving is the other half of the change, covered in e-invoice intake.

The honest framing: this is mostly not an AI project. It is an integration and data-mapping job with a hard deadline, a converter layer between the old system and the outside world while the old system keeps doing what it does well. A model earns its place in three narrow spots, and they are marked below. Everything that ends up inside an invoice is deterministic.

What the old system gets wrong, field by field

Writing XML is the easy part. These are the places where legacy invoice data fails EN 16931, and what the layer does about each.

Mandatory fields that were never stored

XRechnung requires the seller's VAT ID, a buyer reference, payment instructions and an electronic address for both parties, and many old systems never had fields for some of them. Company-wide values come from configuration; per-customer values come from a small table the layer owns, filled in once.

Units written as free text

The ERP says 'Stk', 'St.', 'Stck' and 'Psch'. EN 16931 wants UN/ECE Recommendation 20 codes: H87 or C62 for pieces, LS for a lump sum, HUR for hours, KGM for kilograms. The layer keeps a mapping table, and an unmapped unit stops the invoice rather than being guessed.

VAT rounded per line

Many old systems calculate VAT on each line and add up the rounded amounts. EN 16931 calculates it per rate on the summed net amounts, so the two can differ by a cent and the file fails validation. The layer recomputes by the standard's method and compares; any difference stops the invoice, and the lasting fix is usually a rounding setting in the ERP, not a patch in the layer.

Credit notes printed as negative invoices

The old system prints a credit note as an invoice with minus signs. The layer issues it as type 381 with positive amounts and the original invoice number in BT-25. The German word Gutschrift can also mean self-billing, which is type 389, so the mapping decides per document type rather than per word.

Customers who still want a PDF

Some accounts teams still want something to look at. ZUGFeRD in the EN 16931 profile answers that: the ERP's familiar print layout, converted to PDF/A-3, with the XML embedded. Before sending, a check confirms that the totals in the picture and in the XML are identical.

The same invoice sent twice

A retry after a mail server timeout must not send the invoice again, and re-running an export must not issue a second XML for the same number. Each invoice number is sent once and logged with the file's hash; a resend is a deliberate action with its own log entry.

One invoice through the converter

Only one step in this path uses a model, and only when the old system offers no data at all. Everything that decides what goes into the invoice is code.

  1. 01 Trigger · Database, export folder or print queue

    The ERP finalizes an invoice

    A new invoice number appears in the invoice table, an export file lands in a folder, or the print spooler produces a PDF. The layer watches whichever of the three the old system can offer.

  2. 02 Plain code · ODBC or CSV

    Read the invoice data

    Header, lines, VAT and customer come straight from the database or the export, read-only. Nothing is retyped.

  3. 03 AI model · Structured output

    Read the print output, when nothing else exists

    For systems with no database access and no export, a vision model extracts the fields from the ERP's own PDF. Every value must then reconcile: lines to net, VAT to rate, total to the printed total. Anything that does not reconcile is not sent.

  4. 04 Plain code

    Map to EN 16931

    Fields go to their business terms (invoice number to BT-1, buyer reference to BT-10, payment terms to BT-20), units to UN/ECE codes, tax keys to VAT categories such as S or AE, and the VAT breakdown is recomputed per rate.

  5. 05 Plain code · KoSIT validator

    Generate and validate

    The layer writes XRechnung in UBL or CII syntax, or a ZUGFeRD PDF/A-3, then runs the KoSIT validator on the XML and keeps its report with the invoice.

  6. 06 Decision

    Does it pass?

    Validation and a totals comparison with the ERP, both in code.

    • Valid, and totals equal the ERP's to the cent then send
    • A validation error, a missing value or any difference from the ERP's totals then stop; the invoice goes to the billing queue with the failing rule in plain words
    • Out of scope: a consumer, a customer abroad or an invoice up to EUR 250 then the ERP's PDF goes out as before, logged as out of scope
  7. 07 Person

    Fix the cause, never the file

    The billing person corrects the master data in the ERP (a missing VAT ID, a unit without a code, an invoice address) and releases the invoice again. Nobody edits generated XML by hand.

  8. 08 Result · SMTP, Peppol access point

    Send once, archive, hand to DATEV

    The e-invoice goes by email, or by Peppol where the customer uses it. One send per invoice number, logged with the file hash; the issued file, its validation report and the delivery receipt are archived as GoBD requires, and the booking data goes to DATEV.

The mapping, as it looks inside the layer

Most of the build is this table, completed for your system. An excerpt for an old ERP with a German print layout:

RE_NR (invoice number)BT-1 Invoice numberCopied as is; a number already sent is refused
Kundenbestellnr.BT-13 Purchase order referenceAlso used as BT-10 when the customer has no other buyer reference
Leitweg-ID (new field)BT-10 Buyer referenceMandatory for public-sector customers; kept in the layer's customer table
Unit 'Stk', 'St.' or 'Stck'BT-130 unit code H87Mapping table; an unmapped unit stops the invoice
Unit 'Psch' (lump sum)BT-130 unit code LSMapping table
'14 Tage 2% Skonto, 30 Tage netto'BT-20 Payment terms, BT-9 Due dateText kept; for XRechnung, the discount also in the #SKONTO# syntax
Tax key 1 or 3BT-151 VAT category S (19%) or AE (reverse charge)Mapping table; AE carries the reverse-charge reason the rules require
Document type 'Gutschrift'BT-3 type 381, or 389 for self-billingDecided per document type; amounts positive, BT-25 names the original invoice
Filling in this table for a real system takes days, not months, and it is where a model helps: it proposes mappings from sample invoices, and each one is confirmed with whoever owns billing.

A first invoice for a new customer

New customers and unusual units are where stops happen. This one is caught before it leaves, fixed at the source, and sent on the next run.

Converter log, Monday 07:02

  1. read_invoice(source: "erp_db", number: "26-10433")customer 10277, first invoice / 6 lines / net EUR 8,941.37 / VAT 19% / 30 days net
  2. map_invoice(number: "26-10433", syntax: "cii")stopped / line 4 unit 'Satz' has no UN/ECE code / customer 10277 has no invoice email address
  3. suggest_mapping(value: "Satz", samples: 40)SET (set) / used for seal kits on 40 past invoices / needs confirmation
  4. Converter · Billing queue

    Invoice 26-10433 has not been sent. Two things are missing: the unit 'Satz' on line 4 has no standard code (suggested: SET, as used for seal kits on 40 earlier invoices), and customer 10277 has no invoice email address. Confirm the unit and add the address in the ERP, and the invoice goes out on the next run.

  5. Billing · Billing queue

    SET is right. Invoice address added to the customer record.

  6. kosit_validate(file: "26-10433.xml")schema valid / business rules: 0 errors / recommendation: accept
  7. check_totals(number: "26-10433")net, VAT and total equal the ERP's figures to the cent
  8. send_invoice(number: "26-10433", format: "zugferd_en16931")sent once by email / hash logged / customer prefers ZUGFeRD
  9. archive(number: "26-10433")file, validation report and delivery receipt stored / booking data queued for DATEV
The model suggested one mapping from the company's own past invoices. A person confirmed it, and code produced everything that ended up in the file. The next invoice with 'Satz' goes straight through.

Where a model helps, and where it stays out

The AI model

  • Proposing field and unit mappings during setup

    It reads sample invoices and suggests which legacy value fits which business term; a person confirms each mapping once.

  • Reading print PDFs when there is no export

    The fallback for systems that offer nothing else, always followed by a reconciliation of every total.

  • Finding values buried in free-text remarks

    Old systems often keep the customer's order number in a remarks field. The model proposes it for BT-13, and a person confirms the pattern.

Plain code

  • Mapping, VAT calculation and XML generation

    An invoice is a legal document, so it is generated the same way every time.

  • Validation

    The KoSIT validator decides, not a model's opinion of the XML.

  • Sending once and archiving

    Idempotent by invoice number and logged with the file hash. The pattern is in integration layer or automation platform.

A person

  • Fixing master data and releasing stopped invoices

    The fix belongs in the ERP, made by whoever owns billing.

  • Agreeing format and channel with each customer

    XRechnung, ZUGFeRD or Peppol is agreed with the customer, not inferred.

The road to 1 January 2027

With the deadline this close, the order of work matters. This is the sequence I would follow.

  1. List every invoice type the ERP produces: invoices, credit notes, down-payment and final invoices, and anything the system calls a Gutschrift.
  2. Collect a few hundred real invoices as test cases, including the strange ones billing remembers.
  3. Complete the mapping table with billing, and agree per customer: XRechnung, ZUGFeRD or Peppol.
  4. Generate every test invoice and run it through the KoSIT validator until the whole set passes.
  5. Send real e-invoices to two or three friendly customers alongside the PDF, and ask what their accounting software shows.
  6. Switch the remaining domestic business customers in groups before year end.
  7. From 1 January 2027, domestic B2B invoices leave only as e-invoices, and the layer's log shows every file and its delivery.

Starting in September leaves room for the two surprises every legacy system holds: an invoice type nobody mentioned, and master data that was never complete.

Upgrade the ERP, switch billing tools, or build a converter?

If your ERP vendor ships an e-invoicing module for your version at a fair price, take it. The vendor maintains it as XRechnung versions change, and nothing I build beats that. For simple billing, lexoffice, sevDesk and easybill create compliant e-invoices out of the box, and DATEV's own invoicing does too for companies already working in DATEV.

A converter layer wins when the old system stays: the upgrade would break years of customizations, the vendor has no answer before January, or billing lives in an Access database or custom software nobody wants to touch. Replacing the ERP to meet a deadline is the riskiest option of all, and a converter buys the time to do that migration properly, as described in legacy code modernization.

E-invoicing service providers also convert as a service, usually priced per document, which suits companies whose ERP can already export clean structured data. The custom part is then only the export, and that can be the cheapest route of the three.

How you would know it is working

A blueprint has no results to report, so here is what I would measure from the first week instead, on your own data.

First-pass validation rate
Share of invoices that pass KoSIT without a stop, by invoice type. It should approach all of them well before January.
Stops by cause
Missing master data, unmapped units, total mismatches. Each cause is fixed once in the ERP, so the list should shrink week by week.
Customer queries and rejections
Invoices customers question or send back, which catches what validation cannot, such as a buyer reference that is valid but wrong.
Finalization to delivery time
From the ERP finalizing an invoice to the send log, to catch runs that stall overnight.

What a build like this costs

This is built as Custom Software Development, which is quoted per scope after a free 30-minute call rather than from a fixed table, because the range of what counts as custom software is too wide for one honest number.

What it costs to run

Running costs are small. The layer runs on an ordinary server or next to the ERP, and the KoSIT validator is free and open source. A Peppol access point adds a per-document or monthly fee if some customers need it, and model usage exists only while the print-reading fallback is in use.

What moves the price

  • How the invoice data can be read: a database with understandable tables, an export file, or only the print output
  • How many invoice types exist beyond plain invoices: credit notes, down-payment and final invoices, self-billing
  • How many customers need something other than email: Peppol, a public-sector portal or their own supplier portal
  • The state of master data: missing VAT IDs, units and invoice addresses are fixed in the ERP, and that work is often larger than the code
  • Whether one company or several legal entities bill from the same system

Who this is for

  • German manufacturers above EUR 800,000 turnover billing from an industry ERP whose e-invoicing upgrade is expensive or not coming
  • Agencies and service firms invoicing from custom software, an Access database or a spreadsheet macro
  • Companies with public-sector customers who need XRechnung with a Leitweg-ID now, not in 2027
  • Firms planning an ERP migration after 2027 that need compliant invoices in the meantime

Questions people ask about this

Who has to issue e-invoices in Germany from 2027?

Any business whose turnover in the previous calendar year exceeded EUR 800,000 must issue e-invoices for domestic B2B sales from 1 January 2027, and every business must from 1 January 2028. Receiving e-invoices has been mandatory for all businesses since 1 January 2025. Invoices to consumers and small invoices up to EUR 250 are outside the obligation.

How do I create an XRechnung from an old ERP?

Read the invoice data the ERP already holds, from its database or an export, map it to the EN 16931 business terms, and generate the XML in UBL or CII syntax. Then validate every file with the KoSIT validator before it leaves. The hard part is rarely the XML; it is the missing master data, the unit codes and the VAT rounding the old system never had to care about.

Can we keep sending PDF invoices after 2027?

Not for domestic B2B invoices once you are above the threshold: from 1 January 2027 those must be structured e-invoices, while smaller businesses may send PDFs until the end of 2027. A ZUGFeRD file is a PDF with the XML embedded, so customers who want something to read still get one, and it counts as an e-invoice when it uses a compliant profile.

XRechnung or ZUGFeRD: which should we send?

Both meet the German requirement. XRechnung is pure XML and is what public-sector customers expect. ZUGFeRD in the EN 16931 profile or higher is a PDF with embedded XML, which suits business customers whose accounts teams still read invoices on screen. The layer produces either one per customer from the same data, so the choice can change later without new work.

Is building an e-invoice converter an AI project?

Mostly not, and I say so upfront. Generating and validating e-invoices is deterministic code, because an invoice is a legal document. A model helps in three places: proposing field and unit mappings during setup, reading the print output when the ERP offers no export, and finding values such as order numbers buried in free-text remarks. People confirm all three.

What does an e-invoice converter cost?

It is custom software, quoted per scope after a free discovery call, because the effort depends on how the old system can be read and how complete its master data is. A system with a readable database and clean customer records is a small project; one that only prints PDFs takes longer and adds the model-based fallback.

Sources