German e-invoices for Medusa v2: XRechnung 3.0, ZUGFeRD / Factur-X (EN 16931) for a seller in Germany, issued on fulfillment and credited on refund. Buyers in Germany (B2B, B2C, public sector), the EU/EEA except Italy and Poland, Switzerland and the UK.
A thin Medusa v2 plugin for German e-invoicing (XRechnung 3.0 / ZUGFeRD, EN 16931): subscribes to , , and — an invoice per fulfillment, a credit note per refund or cancellation — maps the order to 's invoice model, and stores the result — idempotently, with no duplicate documents on event redelivery. No tax logic and no XML live in this package; that's /'s job, kept platform-agnostic.
The seller is in Germany. What each buyer receives — the full list, with the territories refused, is in :
| Seller — tax rules | Buyer | Document | Delivery | Since |
|---|---|---|---|---|
| 🇩🇪 Germany | 🇩🇪 Business or consumer in Germany | ZUGFeRD / Factur-X, profile — or XRechnung 3.0, if you prefer it | File: XML, or PDF/A-3b | 0.1.0 |
| 🇩🇪 Germany | 🇩🇪 Public-sector buyer in Germany, with a Leitweg-ID | XRechnung 3.0 | File: XML, or PDF/A-3b | 0.1.0 |
| 🇩🇪 Germany | 🇪🇺 Any other EU member state, except Italy and Poland; Iceland, Liechtenstein and Norway (EEA) | ZUGFeRD / Factur-X, profile | File: XML, or PDF/A-3b | 0.1.0 |
| 🇩🇪 Germany | 🇨🇭 🇬🇧 Switzerland and the UK | ZUGFeRD / Factur-X, profile | File: XML, or PDF/A-3b | 0.1.0 |
Not supported: 🇮🇹 Italy (SDI), 🇵🇱 Poland (KSeF) — clearance platforms with an XML of their own, which no EN 16931 document can serve; out of scope. A buyer anywhere else, and a seller outside Germany, are refused too.
A PDF/A-3 hybrid from any PDF renderer you supply (including a bundled one, 's ), or XML only. The plugin numbers and issues the invoices itself: next to another plugin that issues invoices, the buyer gets two invoices for one supply — turn invoicing off in the other plugin. Documents are stored in Medusa's own File Module (private), with an admin "E-Invoices" widget on the order page and a Store API endpoint for a customer to fetch their own e-invoice. Each issued or refused document is announced on Medusa's event bus (, ; payload types from ), and an order's documents are readable with the order () — so a shop's own code can mail the invoice to the buyer or hand it to accounting.
Supported: Medusa 2.12–2.15 and 2.18 or later 2.x — the releases the end-to-end suite passes on (a real store, from checkout to a validated invoice, credit note and refund), each minor line run at its latest patch. The peer dependencies declare exactly that range, and on any other release the plugin refuses to start () rather than run where it has not been shown to issue correct invoices. Need another release? A pull request is welcome, or write to hello@normwerk.dev about adapting it.
| Medusa | End-to-end suite | Supported | Note |
|---|---|---|---|
| 2.21.2 | 41/41 | yes | Also the version the plugin is developed and unit-tested against |
| 2.21.1 | 41/41 | yes | |
| 2.21.0 | 41/41 | yes | The suite's default |
| 2.20.1 | 41/41 | yes | |
| 2.19.0 | 41/41 | yes | |
| 2.18.0 | 41/41 | yes | |
| 2.16.0, 2.17.2 | — | no | The plugin refuses to start. Before it did, the suite passed 10 of its then 22 checks there: Medusa charged no VAT on the products in the test store, only on shipping, so every domestic order was refused. Cross-border orders passed |
| 2.15.5 | 41/41 | yes | |
| 2.14.2 | 41/41 | yes | npm installs Medusa 2.14.2 itself only with , plugin or not: requires React 19, Medusa's own dashboard 2.14.2 React 18 |
| 2.13.6 | 41/41 | yes | |
| 2.12.6 | 41/41 | yes | |
| below 2.12 | — | no | Not run: the test store does not start on these releases yet |
Invoices and credit notes are issued for a seller in Germany only; the plugin refuses to start with any other seller country. Buyers can be in Germany (businesses, consumers, public-sector buyers), elsewhere in the EU/EEA except Italy and Poland (their clearance platforms take no EN 16931 document), Switzerland or the UK.
Semantic versioning covers the plugin's documented interface only: its options, the events and with their types in , the documents read with an order (), the Admin and Store API routes, the "E-Invoices" admin widget, the plugin's database tables, the field mapping in the mapping reference, and the dry run's script and arguments (dry run); its report carries a format version of its own. Every other file in the package can be imported — Medusa loads subscribers and routes by their path — but is internal: paths such as or change in any release.
Full setup — configuration, migrations, optional PDF modes — is the quickstart: about 30 minutes from a fresh project to a KoSIT-validated invoice on your first fulfilled order.
Before you turn the plugin on, run it over a period of your past orders on a staging copy — it issues nothing, and reports for every fulfillment whether it would issue the invoice, issue it with a notice, or refuse it and why:
The report names no customer. validates the invoices' XML with the official validators and writes it as Markdown. How to run it and how to read it: dry run.
Part of normwerk/einvoice. See that repository for:
npm install @normwerk/einvoice-medusa @normwerk/einvoice-model @normwerk/einvoice-commerce @normwerk/einvoice-ciinpx medusa exec ./node_modules/@normwerk/einvoice-medusa/.medusa/server/src/scripts/einvoice-dry-run.js from=2026-09-01 to=2026-09-30