W System / Blog / Read incoming XRechnung / ZUGFeRD / Factur-X invoices as JSON

Read incoming XRechnung, ZUGFeRD and Factur-X invoices as JSON

Short answer: German businesses have had to accept e-invoices since 1 January 2025, and those arrive as UBL XML, CII XML or a ZUGFeRD / Factur-X PDF with XML inside. You don't need two XML parsers and a PDF extractor to get the data into your own model. Below you'll find which fields matter, what trips up home-grown parsers, and one HTTP call that turns any of the three into the same JSON (seller, buyer, dates, totals, VAT breakdown, IBAN, lines), with a real example.

What arrives in the inbox

FormatWhat it isWhere the data is
XRechnung (UBL)German CIUS of EN 16931, UBL 2.1 Invoice or CreditNotethe XML file itself
XRechnung (CII)same rules, UN/CEFACT Cross Industry Invoice syntaxthe XML file itself
ZUGFeRD 2.x / Factur-XPDF/A-3 with the invoice XML (CII) embeddedan attachment inside the PDF (factur-x.xml, zugferd-invoice.xml, xrechnung.xml)
Peppol BIS Billing 3.0EN 16931 UBL over the Peppol networkthe XML file itself

What trips up home-grown parsers

One call: e-invoice in, JSON out

Disclosure: I'm the maker of this API (W System). POST https://api.wsystem.dev/einvoice/parse takes the raw file (application/xml or application/pdf) or JSON {"xml": "..."} / {"base64": "..."} and returns one JSON shape for UBL, CII and ZUGFeRD / Factur-X. Values come back as written; it does not validate (use POST /einvoice/validate for the EN 16931 / XRechnung rules). Free for 20 calls a day per IP, or get a free API key (500 units/month); without a key past that, $0.01 per call via x402. AI agents can use the MCP tool parse_einvoice on the W System MCP server.

# official CEN example invoice (EN 16931 validation artefacts 1.3.17, examples/ubl-tc434-example1.xml)
curl -X POST "https://api.wsystem.dev/einvoice/parse" -H "Content-Type: application/xml" --data-binary @ubl-tc434-example1.xml

# a ZUGFeRD / Factur-X PDF works the same way
curl -X POST "https://api.wsystem.dev/einvoice/parse" -H "Content-Type: application/pdf" --data-binary @invoice.pdf

No code yet? Drop the file into the free in-browser validator and click Read as JSON: it calls the same endpoint and shows the fields plus the full JSON (free tier, no key).

Real response from the live API (27 October 2026), lines 3 to 20 left out:

{
  "syntax": "ubl",
  "document_type": "invoice",
  "profile": "EN 16931",
  "customization_id": "urn:cen.eu:en16931:2017",
  "container": {"container": "xml"},
  "invoice": {
    "invoice_number": "12115118",
    "issue_date": "2015-01-09",
    "type_code": "380",
    "currency": "EUR",
    "due_date": "2015-01-09",
    "seller": {"name": "De Koksmaat", "vat_id": "NL8200.98.395.B.01", "legal_registration_id": "57151520",
               "address": {"street": "Postbus 7l", "city": "Velsen-Noord", "postal_code": "1950 AB", "country": "NL"}},
    "buyer": {"name": "ODIN 59", "address": {"street": "POSTBUS 367", "city": "HEEMSKERK", "postal_code": "1960 AJ", "country": "NL"},
              "contact": {"name": "Dhr. J BLOKKER"}},
    "totals": {"line_total": "229.60", "total_without_vat": "229.60", "vat_total": "20.73",
               "total_with_vat": "250.33", "amount_due": "250.33"},
    "vat_breakdown": [
      {"category": "S", "rate": "6", "taxable_amount": "183.23", "tax_amount": "10.99"},
      {"category": "S", "rate": "21", "taxable_amount": "46.37", "tax_amount": "9.74"}
    ],
    "payment": [
      {"means_code": "30", "remittance_information": "Deb. 10202 / Fact. 12115118", "iban": "NL57 RABO 0107307510"},
      {"means_code": "30", "iban": "NL03 INGB 0004489902"}
    ],
    "lines": [
      {"id": "1", "name": "PATAT FRITES 10MM 10KG", "quantity": "2", "unit": "EA", "unit_price": "9.95",
       "net_amount": "19.90", "vat_category": "S", "vat_rate": "6", "seller_item_id": "166022"},
      {"id": "2", "name": "PKAAS 50PL. JONG BEL. 1KG", "quantity": "1", "unit": "EA", "unit_price": "9.85",
       "net_amount": "9.85", "vat_category": "S", "vat_rate": "6", "seller_item_id": "661813"}
      ... 18 more lines
    ]
  },
  "line_count": 20,
  "note": "Values are read as written in the XML (strings, no rounding or recomputation). Reading does not check validity: use POST /einvoice/validate for the EN 16931 / XRechnung rules. Not tax advice."
}

Example file: CEN eInvoicing-EN16931 validation artefacts 1.3.17. The CII version of the same invoice (CII_example1.xml) returns the same values with "syntax": "cii". A ZUGFeRD PDF returns "container": {"container": "pdf", "embedded_file": "factur-x.xml"}.

Read, then validate

curl -X POST "https://api.wsystem.dev/einvoice/validate" -H "Content-Type: application/xml" --data-binary @ubl-tc434-example1.xml

Parse to fill your booking form or match the invoice to a purchase order; validate to decide whether to accept it or ask the supplier for a corrected one.

Get a free API key (500 units a month, no card) and point your inbox handler at /einvoice/parse.

Questions and answers

Do German businesses have to receive e-invoices?

Yes. Since 1 January 2025 every business in Germany must be able to receive structured e-invoices (EN 16931, e.g. XRechnung or ZUGFeRD/Factur-X from the EN 16931 profile up) for domestic B2B supplies; a mailbox for the files is enough to accept them. Issuing becomes mandatory in steps from 2027. See the BMF FAQ on e-invoicing and the W System Germany deadlines page. Receiving is the part most invoicing, bookkeeping and DMS products have to build first.

Which formats does POST /einvoice/parse read?

UBL 2.1 Invoice and CreditNote (incl. XRechnung UBL and Peppol BIS Billing 3.0), UN/CEFACT CII (incl. XRechnung CII), and ZUGFeRD / Factur-X PDFs, where it extracts the embedded XML (factur-x.xml, zugferd-invoice.xml, xrechnung.xml) and reads that. All three return the same JSON shape.

Does it validate the invoice?

No. Parsing only reads values as written: amounts stay strings, nothing is rounded or recomputed, and an invoice that breaks the business rules still parses. To check the EN 16931 and XRechnung business rules (BR-*, BR-DE-*) call POST /einvoice/validate, or paste the file into the free e-invoice validator on wsystem.dev.

What fields come back?

Syntax, document type, profile and CustomizationID; invoice number, type code, currency, issue and due date, notes; seller and buyer (name, VAT ID, legal registration ID, address, contact); references; totals (line total, without VAT, VAT, with VAT, prepaid, amount due); the VAT breakdown per category and rate; payment means with IBAN and remittance text; every line (quantity, unit, price, net amount, VAT category and rate, item IDs); and embedded attachments.

How do I send a PDF?

Send the raw file with Content-Type: application/pdf, or JSON {"base64": "..."}. XML can go raw (application/xml) or as JSON {"xml": "..."}. A PDF without an embedded invoice XML returns HTTP 400 (bad_input), because a plain PDF is not an e-invoice. Maximum file size is 5 MB.

What does it cost?

It shares the free tier with the other W System endpoints: 20 calls a day per IP without a key, or a free API key with 500 units a month. Without a key past the free tier it is $0.01 per call via x402 (USDC on Base). AI agents can call the same parser as the MCP tool parse_einvoice.

Is the invoice stored?

No. The document is parsed in memory and not kept; only a usage counter (endpoint and status) is kept. See the privacy policy on wsystem.dev.

Related

Facts checked 2026-10-27. W System is the maker of this product. Not affiliated with the European Commission. Not legal or tax advice.