Compliant e‑invoices from your code.
Invoice JSON in, compliant XRechnung or ZUGFeRD / Factur-X out — XRechnung checked against the official KoSIT validator, with the exact fix when a rule fails. Try it: the real engine runs below, right in your browser.
<?xml version="1.0" encoding="UTF-8"?> <Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"> <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID> <cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID> <cbc:ID>RE-2026-0042</cbc:ID> <cbc:IssueDate>2026-06-11</cbc:IssueDate> <cbc:DueDate>2026-07-11</cbc:DueDate> <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode> <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode> <cbc:BuyerReference>PO-2026-0117</cbc:BuyerReference> <cac:AccountingSupplierParty> <cac:Party> <cbc:EndpointID schemeID="EM">billing@acme.example</cbc:EndpointID> <cac:PostalAddress> <cbc:CityName>Berlin</cbc:CityName> <cbc:PostalZone>10115</cbc:PostalZone> <cac:Country> <cbc:IdentificationCode>DE</cbc:IdentificationCode> </cac:Country> </cac:PostalAddress> <cac:PartyTaxScheme> <cbc:CompanyID>DE123456789</cbc:CompanyID> <cac:TaxScheme> <cbc:ID>VAT</cbc:ID> </cac:TaxScheme> </cac:PartyTaxScheme> <cac:PartyLegalEntity> <cbc:RegistrationName>Acme GmbH</cbc:RegistrationName> </cac:PartyLegalEntity> <cac:Contact> <cbc:Name>Billing</cbc:Name> <cbc:Telephone>+49 30 1234567</cbc:Telephone> <cbc:ElectronicMail>billing@acme.example</cbc:ElectronicMail> </cac:Contact> </cac:Party> </cac:AccountingSupplierParty> <cac:AccountingCustomerParty> <cac:Party> <cbc:EndpointID schemeID="EM">ap@kunde.example</cbc:EndpointID> <cac:PostalAddress> <cbc:CityName>München</cbc:CityName> <cbc:PostalZone>80331</cbc:PostalZone> <cac:Country> <cbc:IdentificationCode>DE</cbc:IdentificationCode> </cac:Country> </cac:PostalAddress> <cac:PartyLegalEntity> <cbc:RegistrationName>Kunde AG</cbc:RegistrationName> </cac:PartyLegalEntity> <cac:Contact> <cbc:ElectronicMail>ap@kunde.example</cbc:ElectronicMail> </cac:Contact> </cac:Party> </cac:AccountingCustomerParty> <cac:PaymentMeans> <cbc:PaymentMeansCode>58</cbc:PaymentMeansCode> <cac:PayeeFinancialAccount> <cbc:ID>DE89370400440532013000</cbc:ID> </cac:PayeeFinancialAccount> </cac:PaymentMeans> <cac:TaxTotal> <cbc:TaxAmount currencyID="EUR">228.00</cbc:TaxAmount> <cac:TaxSubtotal> <cbc:TaxableAmount currencyID="EUR">1200.00</cbc:TaxableAmount> <cbc:TaxAmount currencyID="EUR">228.00</cbc:TaxAmount> <cac:TaxCategory> <cbc:ID>S</cbc:ID> <cbc:Percent>19</cbc:Percent> <cac:TaxScheme> <cbc:ID>VAT</cbc:ID> </cac:TaxScheme> </cac:TaxCategory> </cac:TaxSubtotal> </cac:TaxTotal> <cac:LegalMonetaryTotal> <cbc:LineExtensionAmount currencyID="EUR">1200.00</cbc:LineExtensionAmount> <cbc:TaxExclusiveAmount currencyID="EUR">1200.00</cbc:TaxExclusiveAmount> <cbc:TaxInclusiveAmount currencyID="EUR">1428.00</cbc:TaxInclusiveAmount> <cbc:PayableAmount currencyID="EUR">1428.00</cbc:PayableAmount> </cac:LegalMonetaryTotal> <cac:InvoiceLine> <cbc:ID>1</cbc:ID> <cbc:InvoicedQuantity unitCode="C62">10</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="EUR">1200.00</cbc:LineExtensionAmount> <cac:Item> <cbc:Name>Consulting services</cbc:Name> <cac:ClassifiedTaxCategory> <cbc:ID>S</cbc:ID> <cbc:Percent>19</cbc:Percent> <cac:TaxScheme> <cbc:ID>VAT</cbc:ID> </cac:TaxScheme> </cac:ClassifiedTaxCategory> </cac:Item> <cac:Price> <cbc:PriceAmount currencyID="EUR">120</cbc:PriceAmount> </cac:Price> </cac:InvoiceLine> </Invoice>
Building invoicing into your product? 12 months Growth free for the first 10 design partners→
Receiving e‑invoices: mandatory for every German business since Jan 2025 · issuing follows from Jan 2027 · France starts Sep 2026. Mandate checklist →
Errors you can actually fix.
Every other validator hands you a Schematron rule code and wishes you luck. We return the rule, the path in your JSON, what's wrong, and how to fix it.
A rule code. Good luck.
[error] BR-DE-15 | XRechnung_3.0 | severity=fatal cvc-complex-type.2.4.b: The content of element 'cac:PartyIdentification' is not complete. One of '{urn:oasis:names:specification:ubl:schema:xsd: CommonBasicComponents-2}ID' is expected. (line 47, col 28)
The exact fix.
A typed report: rule, severity, the path in your request, a human message and a concrete fix — never a silently invalid document.
{
"valid": false,
"format": "xrechnung-3.0",
"profile": "XRechnung 3.0.2 (UBL 2.1)",
"tier": "schematron",
"counts": {
"errors": 1,
"warnings": 0
},
"issues": [
{
"severity": "error",
"rule": "BR-DE-15",
"path": "invoice.buyer_reference",
"message": "Buyer reference (BT-10) is missing. XRechnung requires it; public-sector buyers in Germany use their Leitweg-ID here.",
"fix": "Set invoice.buyer_reference. Leitweg-ID format: 04011000-1234512345-06.",
"docs_url": "https://normbill.com/docs/rules/br-de-15",
"location": "/ubl:Invoice/cbc:BuyerReference"
}
]
}Speaks your JSON.
Official findings arrive as BT numbers and XPath. We reverse-map every one onto the field in your request — so the fix lands where you typed it.
Validated before you see it.
Every XRechnung has already survived all three — the KoSIT validator has the final word. ZUGFeRD / Factur-X and Peppol BIS are checked at tier 1.
Your first compliant invoice in five minutes.
Send invoice data as JSON. Get back validated XRechnung XML or a ZUGFeRD / Factur-X hybrid PDF — plus a full validation report. Plain REST from any language, no SDK required.
curl https://api.normbill.com/v1/invoices/generate \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "format": "xrechnung-3.0", "invoice": { "number": "INV-2026-0001", "issue_date": "2026-06-15", "due_date": "2026-07-15", "buyer_reference": "04011000-1234512345-06", "seller": { "name": "Muster Lieferant GmbH", "vat_id": "DE123456789", "address": { "country": "DE", "city": "Berlin", "postal_code": "10115" }, "contact": { "name": "Billing", "phone": "+49 30 1234567", "email": "billing@lieferant.example" } }, "buyer": { "name": "Beispiel Kunde AG", "address": { "country": "DE", "city": "Hamburg", "postal_code": "20095" }, "contact": { "email": "ap@kunde.example" } }, "payment": { "iban": "DE89370400440532013000" }, "lines": [{ "name": "Beratungsleistung", "qty": 10, "unit_price": 100, "vat": 19 }] } }'
Everything the mandate requires.
One POST, validated.
XRechnung (UBL or CII) and Peppol BIS 3.0 from the same JSON — XRechnung checked against the official KoSIT validator before you get it back.
POST /v1/invoices/generateBoth directions.
Parse inbound UBL and CII (ZUGFeRD) into typed invoice JSON; send ZUGFeRD / Factur-X hybrid PDF/A-3 on paid plans.
POST /v1/invoices/parsePlain REST, typed clients.
TypeScript and PHP clients, an MCP server for AI agents, an OpenAPI spec, RFC 9457 errors — and a browser playground running the real engine.
Nothing stored.
Invoices are processed in memory and returned — never persisted, excluded from logs. EU-hosted, AVV (DPA) included.
GDPR · EU-hosted12 months of Growth, free — for the first 10 product teams.
You're building invoicing into your software and want it mandate-ready before the Q4 rush. As a design partner you get the Growth plan free for a year (worth €1,788) and the founder wiring the integration with you — in exchange for a logo, an honest quote, and one feedback call.
The full product, free for a year
- Growth plan for 12 months — every format, every feature
- Direct line to the founder; we open the integration PR into your repo
- Roadmap priority (GoBD archive, Peppol transport)
Proof that it works
- Permission to show your logo on normbill.com
- A 1–2 sentence quote after you ship
- One 30-minute feedback call
Built for product teams
- Vertical SaaS whose users invoice from your product
- You can ship an export path in weeks, not quarters
- Not for one-off SMB invoices — that needs an app, not an API
Start free. No sales call required.
You pay only for documents you produce or parse. Validation, retries and failed calls are free.
All prices excl. VAT. German customers: +19% VAT at checkout. EU B2B with a valid VAT ID: reverse charge.
50 documents a month, official KoSIT validation for XRechnung, test & live keys. No card required.
Start free →Solo
≈ €0.038 per document
Beyond your quota, while metered billing is active on your subscription: €0.06 per extra document, capped at 2× the plan fee. Otherwise calls stop at the quota with a 429.
- 500 documents / month
- ZUGFeRD / Factur-X hybrid PDF
- Generate, validate & parse
- Email support
Starter
≈ €0.02 per document
Beyond your quota, while metered billing is active on your subscription: €0.04 per extra document, capped at 2× the plan fee. Otherwise calls stop at the quota with a 429.
- 2,500 documents / month
- ZUGFeRD / Factur-X hybrid PDF
- Generate, validate & parse
- Email support
Growth
≈ €0.012 per document
Beyond your quota, while metered billing is active on your subscription: €0.02 per extra document, capped at 2× the plan fee. Otherwise calls stop at the quota with a 429.
- 12,000 documents / month
- ZUGFeRD / Factur-X hybrid PDF
- Priority support
- Pay by invoice (SEPA, net-30) on request
75,000+ documents a month? From €690/month excl. VAT on an annual contract: dedicated support, an EU data-residency guarantee, pay by invoice (SEPA, net-30).
Talk to us →Questions developers actually ask.
Is this compliant with the German E-Rechnungspflicht?
The output conforms to EN 16931, the European standard the German mandate is based on. XRechnung documents follow the current KoSIT specification and are validated against the official KoSIT Schematron before you get them back; ZUGFeRD output is valid Factur-X with structural EN 16931 checks. Compliance of the content (correct VAT treatment, mandatory references for your buyer) still depends on the data you send — which is exactly what the validation report tells you about.
XRechnung vs. ZUGFeRD — which one do I need?
XRechnung is pure XML — required for invoicing German public authorities (B2G) and common in B2B. ZUGFeRD / Factur-X is a normal PDF with the same structured XML embedded, so humans and machines both read it. Both satisfy the mandate; many teams send ZUGFeRD to businesses and XRechnung to government. The API generates either from the same JSON.
Do you store our invoice data?
No. Invoices are processed in memory and returned; nothing is persisted, and request bodies are excluded from our logs. EU-hosted infrastructure, GDPR-first — there is no retention setting to configure because there is nothing retained.
Can I validate invoices I generated somewhere else?
Yes — POST XRechnung (UBL or CII) to /v1/invoices/validate for authoritative KoSIT validation; ZUGFeRD / Factur-X CII is checked at the structural EN 16931 tier today. Either way you get a machine-readable report: every failed rule with its ID, severity, a plain-language message and a suggested fix. Or try the free validator with no key. Validation is free within a generous fair-use allowance — five times your plan's monthly document quota — and never counts against your billable documents.
We're a SaaS that issues invoices for our users — can we embed this?
That's the core use case. One API key, and a free-form metadata object on every invoice for your own per-tenant correlation. The API responds synchronously — your users never see normbill, they just get compliant invoices out of your product. At platform volume, the Platform tier adds pay-by-invoice billing (SEPA, net-30), dedicated support and an EU data-residency guarantee.
Can you deliver invoices over Peppol?
The API generates Peppol BIS Billing 3.0 UBL today, so your documents are network-ready. Transmission over the Peppol network (via a certified access point) is on the roadmap — generation and validation come first, because that's the part every team needs on day one.
What happens when validation fails?
You get a 422 with field-level errors: the rule that fired, the path in your JSON that caused it, a plain-language message, and a suggested fix. The API never silently returns an invalid document.
What happens when I run out of quota?
Only successful documents count against your quota — failed attempts cost nothing, and validation has its own generous free allowance. The quota runs with your billing period; on annual plans twelve months' worth of documents pool across the contract year. From 80% usage every response carries an X-Quota-Warning header, so nothing surprises you. On paid plans with metered overage active on your subscription, extra documents are billed at the per-document rate shown on your tariff (capped at 2× the plan fee); otherwise calls stop at the quota with a clear 429 instead of being billed. The Free plan always returns a 429 with an upgrade link. sk_test_ keys are never billed.
How do I reach a human?
Email support@normbill.com — for support, questions about the docs, or anything this FAQ doesn't cover. A practical getting-started guide lives in the public docs.
Be mandate‑ready this afternoon.
Free key, 50 invoices a month, full validation. Upgrade only when you're shipping real volume — no sales call, no contract, no credit card.