Live — instant API keys, no sales call

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.

POST/v1/invoices/generate
200RE-2026-0042.xml · 3.9 kB · UBL 2.1
<?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>
valid — EN 16931 · XRechnung 3.0 structural checksEdit the JSON or pick an example — runs in your browserOpen the full playground →

Receiving e‑invoices: mandatory for every German business since Jan 2025 · issuing follows from Jan 2027 · France starts Sep 2026. Mandate checklist →

Validation

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.

THE USUAL EXPERIENCE

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)
NORMBILL 422

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"
    }
  ]
}
FIELD MAPPING

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.

BT-10 · cbc:BuyerReferenceinvoice.buyer_reference
BT-31 · cac:PartyTaxSchemeinvoice.seller.vat_id
BG-6 · cac:Contactinvoice.seller.contact
THREE TIERS

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.

01Structural rulesevery format, instant, runs in the browser too
02XSD schemaUBL / CII schema, inside the KoSIT run
03KoSIT Schematronthe official validator, pinned — XRechnung
Quickstart

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 }]
  } }'
The platform

Everything the mandate requires.

GENERATE + VALIDATE

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/generate
PARSE + PDF

Both 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/parse
SDKS + PLAYGROUND

Plain 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.

PRIVACY

Nothing stored.

Invoices are processed in memory and returned — never persisted, excluded from logs. EU-hosted, AVV (DPA) included.

GDPR · EU-hosted
Founding offer

12 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.

YOU GET

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)
WE ASK

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
FIT

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
Pricing

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.

FREE

50 documents a month, official KoSIT validation for XRechnung, test & live keys. No card required.

Start free →

Solo

€19/mo

≈ €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
Choose Solo
MOST POPULAR

Starter

€49/mo

≈ €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
Choose Starter

Growth

€149/mo

≈ €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
Choose Growth
PLATFORM

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 →
30-day validation guarantee: if an XRechnung we generate fails the official KoSIT validator, we fix it free — or refund the month.
FAQ

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.

EU-hostedNo invoice data storedGDPR-first30-day validation guarantee

Spotted something?

Bug, missing feature, wrong validation result — tell us. The page you're on is attached automatically; email optional.