Shop orders become e-invoices automatically
A completed order goes in, a checked XRechnung or ZUGFeRD comes out — with no manual step in the backend.
The shop already knows the whole order: line items, tax rates, shipping, billing address. What it lacks is the format a business customer or a public body has to accept. One trigger on the order status, one call, and the invoice exists as XRechnung or as a ZUGFeRD PDF — for WooCommerce, Shopware, JTL and Magento through their integration pages, for everything else through a workflow or the REST interface.
What comes in
The order with line items, quantities, unit prices and tax rates
Shipping and discount rows, which belong in the invoice as their own line
The billing address and, for business customers, the VAT ID
The order status as the trigger, e.g. “completed”
For public sector buyers: the Leitweg-ID on the customer record
What this solves
The trigger sits in the shop, not in a calendar
The invoice is created when the order completes — not in a nightly job whose failure only shows at month end. In WooCommerce, Shopware, JTL and Magento the trigger hangs off the order status.
One record, two formats
The same order record yields an XRechnung for the business customer and a ZUGFeRD PDF for everyone else. You do not maintain two invoicing routes side by side.
Checked before it leaves the shop
Before generating, the validate endpoint checks the invoice data against the KoSIT rules. If the tax category or the contact is missing, the response names the rule and the field — the order itself is untouched.
Credit notes and cancellations belong to the job
A return is not an invoice with a minus in front. The document type credit_note models it and carries the original invoice number as a reference, so the recipient does not book it twice.
One real example
The line item from the recipe “Generate and send a ZUGFeRD PDF”, in the shape an order produces.
{ "invoice": { "items": [ { "position": 1, "description": "Beratungsleistung", "quantity": 10, "unit": "HUR", "unitPrice": 150, "taxRate": 19, "netAmount": 1500, "taxAmount": 285, "grossAmount": 1785 } ], "taxSummary": [ { "taxRate": 19, "netAmount": 1500, "taxAmount": 285 } ], "subtotal": 1500, "total": 1785 }}POST /api/v1/invoice/DE/zugferd/generate
10 × 150.00 € make 1,500.00 € net, 19 % make 285.00 € tax, total 1,785.00 €. The response is a Base64-encoded PDF/A-3 with embedded EN 16931 XML: the customer sees a PDF, their system reads the XML.
The full recipeThe endpoints involved
- Invoice CreatorLive
POST /api/v1/invoice/{countryCode}/{format}/generate
- ValidatorLive
POST /api/v1/invoice/{countryCode}/validate
Compared to the alternative
The alternative is a shop plugin that builds the invoice itself. Then conformance depends on that plugin's release cadence and stops at the shop boundary — the plugin comparison shows what that means in practice.
Read the comparisonHow it runs
- 1
Set the trigger: order status “completed”, in the shop or in the workflow.
- 2
POST /api/v1/invoice/DE/validate with the order data — the run continues only on a clean result.
- 3
POST /api/v1/invoice/DE/xrechnung/generate or .../zugferd/generate, attach the file to the order and send it.
What it costs at this volume
Around 500 invoices per month fit the Starter plan at 23 € per month.
All prices net, plus VAT · 20 % off when billed annually · Free tier without a credit card
All plansLimits
- The Shopify app is submitted for Shopify App Store review and not publicly installable yet.
- Peppol dispatch is not available yet (planned 2027).
- Master data upkeep — Leitweg-ID, tax categories, VAT ID — stays your job.
Frequently asked questions
Do I need a separate plugin for every shop?
No. WooCommerce, Shopware, JTL and Magento each have an integration page with the route that fits; beyond those a workflow or a call from your shop code is enough. The API is the same in every case.
Does every order count against my quota?
Every generated invoice is one API call. A pure validation generates nothing and is not counted as generation; it still needs a valid key, and with an exhausted quota the API answers 429.
What happens with a return?
You generate a credit note with document type credit_note and a reference to the original invoice number. Amounts stay positive — the document type sets the direction, not the sign.