<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thor</title>
    <description>The latest articles on DEV Community by Thor (@thor_4e886628f33fca7fa8df).</description>
    <link>https://dev.to/thor_4e886628f33fca7fa8df</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4103309%2F76a2b2ab-14b2-4899-a04b-85caf241c618.png</url>
      <title>DEV Community: Thor</title>
      <link>https://dev.to/thor_4e886628f33fca7fa8df</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thor_4e886628f33fca7fa8df"/>
    <language>en</language>
    <item>
      <title>Stripe Invoice JSON EN 16931 BT-* (Germany 2026)</title>
      <dc:creator>Thor</dc:creator>
      <pubDate>Mon, 31 Aug 2026 20:48:40 +0000</pubDate>
      <link>https://dev.to/thor_4e886628f33fca7fa8df/stripe-invoice-json-en-16931-bt-germany-2026-cda</link>
      <guid>https://dev.to/thor_4e886628f33fca7fa8df/stripe-invoice-json-en-16931-bt-germany-2026-cda</guid>
      <description>&lt;p&gt;Stripe Invoicing stores an invoice &lt;em&gt;record&lt;/em&gt; and exposes it on the API and on webhooks. It does &lt;strong&gt;not&lt;/strong&gt; emit a legally compliant German e-invoice file. Stripe’s own e-invoicing docs say so: you either install a Marketplace app (Billit is the named partner) or you build a webhook that maps the Invoice object into EN 16931 XML yourself. This article is that map — Stripe JSON paths to CEN business terms (&lt;code&gt;BT-*&lt;/code&gt;) and the German CIUS (XRechnung 3.0.2). You can implement it in any language. No hosted e-invoicing API is required for the mapping itself.&lt;/p&gt;

&lt;p&gt;This is not tax advice. Never invent a USt-IdNr / VAT ID.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spec pin (31 Aug 2026)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pin&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Semantic model&lt;/td&gt;
&lt;td&gt;EN 16931-1:2017 (the 2026 recast is &lt;strong&gt;not&lt;/strong&gt; the production CIUS yet)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;German CIUS&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;XRechnung 3.0.2&lt;/strong&gt;, KoSIT validator configuration &lt;strong&gt;2026-01-31&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CustomizationID &lt;strong&gt;BT-24&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0&lt;/code&gt; — yes, &lt;code&gt;_3.0&lt;/code&gt;, not &lt;code&gt;_3.0.2&lt;/code&gt;. The old 2.x form &lt;code&gt;xoev-de:kosit:standard:xrechnung_&lt;/code&gt; is wrong (BR-DE-21).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProfileID &lt;strong&gt;BT-23&lt;/strong&gt; (UBL)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;urn:fdc:peppol.eu:2017:poacc:billing:01:1.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Syntax A&lt;/td&gt;
&lt;td&gt;UBL 2.1 Invoice (what KoSIT’s XRechnung Invoice scenario matches)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Syntax B&lt;/td&gt;
&lt;td&gt;UN/CEFACT CII, ZUGFeRD &lt;strong&gt;2.5.2&lt;/strong&gt; / Factur-X &lt;strong&gt;1.09.2&lt;/strong&gt;, EN 16931 profile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CII guideline &lt;strong&gt;BT-24&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:en16931&lt;/code&gt; (&lt;code&gt;1p0&lt;/code&gt; is the Factur-X family token, not the 1.09.2 package version)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XRechnung 4.0&lt;/td&gt;
&lt;td&gt;Preview only as of 31 Aug 2026; no production bundle, CEN syntax bindings still outstanding&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ZUGFeRD 2.5.2 is FeRD’s 4 August 2026 corrigendum of 2.5 (Factur-X 1.09.2), current download, effective 1 September 2026. It does &lt;strong&gt;not&lt;/strong&gt; change the BMF-accepted format family: ZUGFeRD from 2.0.1 onward in the EN 16931 profile (MINIMUM and BASIC-WL are out). ZUGFeRD 2.x &lt;em&gt;is&lt;/em&gt; CII XML. The usual &lt;em&gt;exchange&lt;/em&gt; form is a PDF/A-3 hybrid with that XML embedded; the structured XML is the e-invoice under § 14 UStG.&lt;/p&gt;

&lt;p&gt;Invoice type &lt;strong&gt;BT-3&lt;/strong&gt; is &lt;code&gt;380&lt;/code&gt; (commercial invoice) for this map. Credit notes are a different object (Stripe &lt;code&gt;CreditNote&lt;/code&gt; / type &lt;code&gt;381&lt;/code&gt;) and are out of scope here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receive vs issue (BMF, not a vibe)
&lt;/h2&gt;

&lt;p&gt;Two different duties. Do not collapse them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Receive (already live).&lt;/strong&gt; Since 1 January 2025 every domestic German business — including Kleinunternehmer — must be able to &lt;em&gt;receive&lt;/em&gt; e-invoices. There is no receive exception (BMF FAQ). An e-mail inbox is enough. The statute does not mandate Peppol, a portal, or a specific viewer. There is &lt;strong&gt;no&lt;/strong&gt; separate statutory “must-read” duty; visualization is practical, not the mandate. The structured XML original must be kept unaltered (§ 14b UStG / GoBD). A paper printout is not the original. For a hybrid ZUGFeRD PDF, keeping the structured part is sufficient unless the PDF carries extra tax-relevant data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue (2026 is still the transition).&lt;/strong&gt; Through 31 December 2026 any issuer may still send a “sonstige Rechnung”. Paper is always allowed in that window. An unstructured PDF still needs the recipient’s consent. From 1 January 2027, issuers whose 2026 (prior-year) turnover &lt;strong&gt;exceeded EUR 800,000&lt;/strong&gt; must issue an EN 16931 e-invoice (non-EN-16931 EDI may run through 31 December 2027). From 1 January 2028 remaining in-scope B2B issuers. &lt;strong&gt;Kleinunternehmer stay exempt from issuing&lt;/strong&gt; under § 34a UStDV; they are &lt;strong&gt;not&lt;/strong&gt; exempt from receiving.&lt;/p&gt;

&lt;p&gt;Transport for domestic B2B is not prescribed: e-mail, interface, shared storage, USB stick, or a portal download all count. Peppol is a B2G / reachability regime, not a UStG requirement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Units Stripe will trip you on
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Amounts are &lt;strong&gt;integer cents&lt;/strong&gt;. &lt;code&gt;10000&lt;/code&gt; is EUR 100.00, not 10,000 euro. Divide by 100 with &lt;code&gt;Decimal&lt;/code&gt;, not float.&lt;/li&gt;
&lt;li&gt;Dates are &lt;strong&gt;Unix seconds&lt;/strong&gt; unless noted. &lt;code&gt;status_transitions.finalized_at&lt;/code&gt; / &lt;code&gt;created&lt;/code&gt; / &lt;code&gt;due_date&lt;/code&gt; / &lt;code&gt;period_start&lt;/code&gt; → ISO date (&lt;code&gt;YYYY-MM-DD&lt;/code&gt;) for BT-2 / BT-9 / BT-73 / BT-74.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;currency&lt;/code&gt; is lowercase (&lt;code&gt;eur&lt;/code&gt;). EN 16931 wants &lt;code&gt;EUR&lt;/code&gt; (BT-5).&lt;/li&gt;
&lt;li&gt;Seller legal identity is &lt;strong&gt;not&lt;/strong&gt; on a Stripe Invoice. Overlay it. &lt;strong&gt;Never invent a USt-IdNr.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Prefer &lt;code&gt;tax_behavior: exclusive&lt;/code&gt;. Inclusive Stripe tax must be unpicked &lt;em&gt;before&lt;/em&gt; you fill BT-146 / BT-131; EN 16931 line amounts are net.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A webhook often wraps the Invoice as &lt;code&gt;event.data.object&lt;/code&gt;. Unwrap that first.&lt;/p&gt;

&lt;h2&gt;
  
  
  The field map
&lt;/h2&gt;

&lt;p&gt;Use this table even without a CLI.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stripe field&lt;/th&gt;
&lt;th&gt;Canonical / BT-*&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;number&lt;/code&gt; (fallback &lt;code&gt;id&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;invoice_number&lt;/code&gt; &lt;strong&gt;BT-1&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Rechnungsnummer. Use Stripe &lt;code&gt;id&lt;/code&gt; (&lt;code&gt;in_…&lt;/code&gt;) only if &lt;code&gt;number&lt;/code&gt; is still empty (draft).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;status_transitions.finalized_at&lt;/code&gt; else &lt;code&gt;created&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;issue_date&lt;/code&gt; &lt;strong&gt;BT-2&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Unix → ISO date.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;(fixed &lt;code&gt;380&lt;/code&gt;)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;type_code&lt;/code&gt; &lt;strong&gt;BT-3&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Commercial invoice.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;currency&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;currency&lt;/code&gt; &lt;strong&gt;BT-5&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;eur&lt;/code&gt; → &lt;code&gt;EUR&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;due_date&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;due_date&lt;/code&gt; &lt;strong&gt;BT-9&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Unix → ISO.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;metadata.leitweg_id&lt;/code&gt; or &lt;code&gt;metadata.buyer_reference&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;buyer_reference&lt;/code&gt; &lt;strong&gt;BT-10&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;BR-DE-15 mandatory on every XRechnung&lt;/strong&gt;, not only B2G. B2G: the authority’s Leitweg-ID (do not guess). B2B: buyer reference / PO number.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;note&lt;/code&gt; &lt;strong&gt;BT-22&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Free text.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;period_start&lt;/code&gt; / &lt;code&gt;period_end&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;invoicing period &lt;strong&gt;BT-73 / BT-74&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Leistungszeitraum. Also emit per-line BG-26 from &lt;code&gt;lines.data[].period&lt;/code&gt; when present.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;seller.name&lt;/code&gt; &lt;em&gt;or&lt;/em&gt; &lt;code&gt;metadata.seller_name&lt;/code&gt; &lt;em&gt;or&lt;/em&gt; &lt;code&gt;account_name&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;seller name &lt;strong&gt;BT-27&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Overlay. Stripe &lt;code&gt;account_name&lt;/code&gt; is weak — prefer &lt;code&gt;seller&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;seller.street&lt;/code&gt; / &lt;code&gt;city&lt;/code&gt; / &lt;code&gt;postal_code&lt;/code&gt; / &lt;code&gt;country&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;seller address &lt;strong&gt;BG-5 / BT-35…BT-40&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Overlay.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;seller.vat_id&lt;/code&gt; / &lt;code&gt;metadata.seller_vat&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;BT-31&lt;/strong&gt; USt-IdNr&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Never invented.&lt;/strong&gt; Empty stays empty; a strict check fails BR-DE-16 if the VAT category requires it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;seller.tax_number&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;BT-32&lt;/strong&gt; Steuernummer&lt;/td&gt;
&lt;td&gt;Alternative to BT-31 for some DE cases.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;seller.email&lt;/code&gt; / &lt;code&gt;phone&lt;/code&gt; / &lt;code&gt;contact_name&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;BT-43 / BT-42 / BT-41&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;BR-DE-5 / 6 / 7&lt;/strong&gt; — XRechnung expects seller contact.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;seller.email&lt;/code&gt; as EndpointID scheme &lt;code&gt;EM&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;BT-34&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Seller electronic address (BR-DE-18).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;seller.iban&lt;/code&gt; / &lt;code&gt;bic&lt;/code&gt; / &lt;code&gt;account_name&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;payment &lt;strong&gt;BG-16 / BT-84 / BT-86&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;BR-DE-1.&lt;/strong&gt; Means code &lt;code&gt;58&lt;/code&gt; (SEPA credit transfer). Fixture IBANs are labelled EXAMPLE.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;customer_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;buyer name &lt;strong&gt;BT-44&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;customer_address.line1&lt;/code&gt; / &lt;code&gt;city&lt;/code&gt; / &lt;code&gt;postal_code&lt;/code&gt; / &lt;code&gt;country&lt;/code&gt; / &lt;code&gt;state&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;buyer address &lt;strong&gt;BG-8&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;line1&lt;/code&gt; → street; &lt;code&gt;state&lt;/code&gt; → region.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;customer_email&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;buyer electronic address &lt;strong&gt;BT-49&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;scheme &lt;code&gt;EM&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;customer_tax_ids[]&lt;/code&gt; where &lt;code&gt;type=eu_vat&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;buyer VAT &lt;strong&gt;BT-48&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Also accepts Customer &lt;code&gt;tax_ids.data&lt;/code&gt;. Required for AE / K.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lines.data[].description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;line name &lt;strong&gt;BT-153&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lines.data[].quantity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;BT-129&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lines.data[].price.recurring.interval&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;unit &lt;strong&gt;BT-130&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;month&lt;/code&gt; → &lt;code&gt;MON&lt;/code&gt;; else &lt;code&gt;C62&lt;/code&gt; (one piece).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;lines.data[].price.unit_amount&lt;/code&gt; / 100&lt;/td&gt;
&lt;td&gt;net unit price &lt;strong&gt;BT-146&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Exclusive tax.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;lines.data[].amount&lt;/code&gt; / 100&lt;/td&gt;
&lt;td&gt;line net &lt;strong&gt;BT-131&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;lines.data[].tax_amounts[].tax_rate.percentage&lt;/code&gt; or &lt;code&gt;default_tax_rates[].percentage&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;line rate &lt;strong&gt;BT-152&lt;/strong&gt; / document rate &lt;strong&gt;BT-119&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;DE typically 19 or 7.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;metadata.vat_category&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;line VAT category&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;S&lt;/code&gt; &lt;code&gt;Z&lt;/code&gt; &lt;code&gt;E&lt;/code&gt; &lt;code&gt;AE&lt;/code&gt; &lt;code&gt;K&lt;/code&gt; &lt;code&gt;G&lt;/code&gt; &lt;code&gt;O&lt;/code&gt;. Default &lt;code&gt;S&lt;/code&gt;. You choose the category; the mapper must not.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;metadata.exemption_reason&lt;/code&gt; / &lt;code&gt;exemption_reason_code&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;BT-120 / BT-121&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Required for AE / K / G.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;metadata.kleinunternehmer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;flag&lt;/td&gt;
&lt;td&gt;Forces category &lt;code&gt;E&lt;/code&gt;, tax 0, § 19 note. Does &lt;strong&gt;not&lt;/strong&gt; invent a VAT ID. Issuing stays exempt.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;subtotal&lt;/code&gt; / &lt;code&gt;tax&lt;/code&gt; / &lt;code&gt;total&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;cross-check only&lt;/td&gt;
&lt;td&gt;Recompute canonical totals with &lt;code&gt;Decimal&lt;/code&gt;, 2 places, &lt;code&gt;ROUND_HALF_UP&lt;/code&gt;. Do not trust float.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;BT-24, BT-23, payment means code &lt;code&gt;58&lt;/code&gt;, and type code &lt;code&gt;380&lt;/code&gt; do not exist on the Stripe object. They are constants of the CIUS / syntax you emit, not Invoice fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seller overlay
&lt;/h2&gt;

&lt;p&gt;Stripe will not give you BT-31, BT-32, BT-41–43, BT-34, or BG-16. Merge a seller object from your own master data (CLI flag, env file, or a top-level &lt;code&gt;seller&lt;/code&gt; key you add &lt;em&gt;after&lt;/em&gt; the webhook — never from a guessed string).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Beispiel GmbH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"street"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Musterstraße 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Berlin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"postal_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10115"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"vat_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DE123456789"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rechnung@beispiel.example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+49-30-000000-0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"contact_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ina Beispiel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iban"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DE89370400440532013000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bic"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"COBADEFFXXX"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;DE123456789&lt;/code&gt; and the IBAN above are &lt;strong&gt;textbook examples&lt;/strong&gt;, not live identifiers. Put &lt;em&gt;your&lt;/em&gt; values. If you omit &lt;code&gt;vat_id&lt;/code&gt;, mapping can still run; a BR-DE-16 check must fail rather than invent &lt;code&gt;DE000000000&lt;/code&gt;, &lt;code&gt;TODO&lt;/code&gt;, or &lt;code&gt;XXX&lt;/code&gt;. Reject those placeholders on sight.&lt;/p&gt;

&lt;p&gt;Leitweg-ID (public-sector buyer routing id, &lt;code&gt;Grobadressat-Feinadressat-Prüfziffer&lt;/code&gt;) comes from the authority, not from &lt;code&gt;customer_address&lt;/code&gt;. Put it in &lt;code&gt;metadata.leitweg_id&lt;/code&gt;. You cannot derive it from Stripe customer fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Stripe will never give you
&lt;/h2&gt;

&lt;p&gt;Seller USt-IdNr, Steuernummer, IBAN, Leitweg-ID, VAT category &lt;code&gt;K&lt;/code&gt; / &lt;code&gt;AE&lt;/code&gt; / &lt;code&gt;G&lt;/code&gt; with VATEX codes, Kleinunternehmer status. Those are master data. The map exists so a webhook can merge them locally without sending names, VAT IDs, and line items to a hosted e-invoicing API.&lt;/p&gt;

&lt;p&gt;Also not on the Invoice: Handelsregister number, correct seller postal address (Stripe &lt;code&gt;account_name&lt;/code&gt; is a display string), and any guarantee that &lt;code&gt;customer_tax_ids&lt;/code&gt; is populated. If you need BT-48, fetch Customer &lt;code&gt;tax_ids&lt;/code&gt; (type &lt;code&gt;eu_vat&lt;/code&gt;) and merge it.&lt;/p&gt;

&lt;h2&gt;
  
  
  VAT categories and rounding
&lt;/h2&gt;

&lt;p&gt;Commercial rounding: &lt;code&gt;Decimal&lt;/code&gt;, two fractional digits, &lt;code&gt;ROUND_HALF_UP&lt;/code&gt;. Per tax group: tax = round(taxable amount × rate / 100). Net + tax = gross (&lt;strong&gt;BT-109 + BT-110 = BT-112&lt;/strong&gt;). Do not copy Stripe &lt;code&gt;subtotal&lt;/code&gt; / &lt;code&gt;tax&lt;/code&gt; / &lt;code&gt;total&lt;/code&gt; into those BTs as source of truth — they are a cross-check against a float-ish JSON number.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Meaning (DE)&lt;/th&gt;
&lt;th&gt;Typical rate&lt;/th&gt;
&lt;th&gt;BT-120 / BT-121&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;S&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Standard / reduced&lt;/td&gt;
&lt;td&gt;19 or 7&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Z&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero rate&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;reason recommended&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;E&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Exempt&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;reason text required (Kleinunternehmer § 19)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reverse charge&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;VATEX-EU-AE&lt;/code&gt; + text; tax amount &lt;strong&gt;0&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;K&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Intra-community supply&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;VATEX-EU-IC&lt;/code&gt;; delivery country + buyer VAT ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;G&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Export, third country&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;VATEX-EU-G&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;O&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Outside scope&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;VATEX-EU-O&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Worked S-19: net 100.00 + tax 19.00 = gross 119.00. Worked S-7: 10 × 29.00 = 290.00 net; tax 20.30; gross 310.30.&lt;/p&gt;

&lt;p&gt;Wrong category is wrong tax. A mapper that “picks S because Germany” on an intra-community line is not doing you a favour. For AE / K / G, tax must be &lt;strong&gt;0&lt;/strong&gt; (not 19% with a note). Buyer VAT ID (BT-48) is required for AE / K.&lt;/p&gt;

&lt;h2&gt;
  
  
  BR-DE rules this map is designed around
&lt;/h2&gt;

&lt;p&gt;XRechnung is EN 16931 plus German business rules. The ones Stripe-shaped payloads miss first:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;BT&lt;/th&gt;
&lt;th&gt;Typical miss&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BR-02&lt;/td&gt;
&lt;td&gt;BT-1&lt;/td&gt;
&lt;td&gt;Draft Invoice with empty &lt;code&gt;number&lt;/code&gt; and you forgot the &lt;code&gt;id&lt;/code&gt; fallback.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BR-DE-15&lt;/td&gt;
&lt;td&gt;BT-10&lt;/td&gt;
&lt;td&gt;No &lt;code&gt;metadata.leitweg_id&lt;/code&gt; / &lt;code&gt;buyer_reference&lt;/code&gt;. Mandatory on &lt;strong&gt;every&lt;/strong&gt; XRechnung.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BR-DE-1&lt;/td&gt;
&lt;td&gt;BG-16&lt;/td&gt;
&lt;td&gt;No seller IBAN. Payment means code &lt;code&gt;58&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BR-DE-5/6/7&lt;/td&gt;
&lt;td&gt;BT-41/42/43&lt;/td&gt;
&lt;td&gt;No &lt;code&gt;contact_name&lt;/code&gt; / &lt;code&gt;phone&lt;/code&gt; / &lt;code&gt;email&lt;/code&gt; on the overlay.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BR-DE-16&lt;/td&gt;
&lt;td&gt;BT-31&lt;/td&gt;
&lt;td&gt;Empty seller VAT ID / tax number while category is S/Z/E/AE/K/G.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BR-DE-18&lt;/td&gt;
&lt;td&gt;BT-34&lt;/td&gt;
&lt;td&gt;No seller EndpointID; use email + scheme &lt;code&gt;EM&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BR-DE-21&lt;/td&gt;
&lt;td&gt;BT-24&lt;/td&gt;
&lt;td&gt;CustomizationID not exactly the &lt;code&gt;_3.0&lt;/code&gt; URN above.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BR-AE-02&lt;/td&gt;
&lt;td&gt;BT-48&lt;/td&gt;
&lt;td&gt;Reverse charge / intra-community without buyer VAT ID.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BR-AE-10&lt;/td&gt;
&lt;td&gt;BT-120&lt;/td&gt;
&lt;td&gt;AE/K/G without exemption reason / VATEX code.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BR-IC-12&lt;/td&gt;
&lt;td&gt;BT-80&lt;/td&gt;
&lt;td&gt;Intra-community without delivery country.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BR-CO-10&lt;/td&gt;
&lt;td&gt;BT-106&lt;/td&gt;
&lt;td&gt;Sum of lines ≠ sum of BT-131 (float cents).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BR-DE-TMP-32&lt;/td&gt;
&lt;td&gt;BT-72 / BG-14 / BG-26&lt;/td&gt;
&lt;td&gt;Information only: no actual delivery date &lt;em&gt;and&lt;/em&gt; no invoicing period. Set &lt;code&gt;period_start&lt;/code&gt; / &lt;code&gt;period_end&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Local structural checks are &lt;strong&gt;not&lt;/strong&gt; the official KoSIT validator. Before you send to ZRE / OZG-RE / a buyer portal, run KoSIT on &lt;em&gt;your&lt;/em&gt; file with &lt;em&gt;your&lt;/em&gt; identity fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two files, two BT-24 values
&lt;/h2&gt;

&lt;p&gt;Same canonical invoice, two syntaxes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;XRechnung 3.0.2 UBL Invoice&lt;/strong&gt; — BT-24 is the XRechnung 3.0 CIUS URN. This is what German public buyers and many B2B recipients mean by “XRechnung”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ZUGFeRD 2.5.2 / Factur-X 1.09.2 CII&lt;/strong&gt; — BT-24 is the Factur-X EN 16931 guideline URN. KoSIT’s &lt;em&gt;XRechnung&lt;/em&gt; scenarios will not match that file (&lt;code&gt;noScenarioMatched&lt;/code&gt;). That is expected: it is not an XRechnung CIUS document. BMF still lists ZUGFeRD ≥ 2.0.1 EN 16931 as an accepted e-invoice format. Do not relabel a Factur-X file as XRechnung to force a KoSIT pass.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can emit CII XML without writing a PDF/A-3 hybrid. That XML is still an e-invoice under § 14 UStG; the hybrid PDF is a convenience wrapper. A received hybrid can be read by extracting the embedded &lt;code&gt;factur-x.xml&lt;/code&gt; / &lt;code&gt;zugferd-invoice.xml&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kleinunternehmer
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;metadata.kleinunternehmer&lt;/code&gt; is a &lt;em&gt;receive/issue-policy&lt;/em&gt; flag, not a VAT ID generator. If set: category &lt;code&gt;E&lt;/code&gt;, tax 0, a § 19 note. It must not fill BT-31 with a dummy. Issuing structured EN 16931 remains exempt under § 34a UStDV through the current mandate. Receiving is already mandatory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validation honesty
&lt;/h2&gt;

&lt;p&gt;Local arithmetic and a handful of BR-DE checks are &lt;strong&gt;not&lt;/strong&gt; the official validator. Before you send a file to ZRE, OZG-RE, or a buyer, run the &lt;strong&gt;KoSIT validator&lt;/strong&gt; on &lt;em&gt;your&lt;/em&gt; XML, with &lt;em&gt;your&lt;/em&gt; identity fields filled.&lt;/p&gt;

&lt;p&gt;Production pin as of 31 August 2026: KoSIT validator &lt;strong&gt;1.6.3&lt;/strong&gt; plus XRechnung configuration &lt;strong&gt;2026-01-31&lt;/strong&gt; (XRechnung 3.0.2). The configuration bundle may still mention engine 1.6.0 in its notes; 1.6.3 is the current engine tag and runs the same 3.0.2 scenarios.&lt;/p&gt;

&lt;p&gt;KoSIT’s XRechnung Invoice scenario matches &lt;strong&gt;UBL&lt;/strong&gt; with the &lt;code&gt;_3.0&lt;/code&gt; CustomizationID. A ZUGFeRD/Factur-X &lt;strong&gt;CII&lt;/strong&gt; file will typically return &lt;code&gt;noScenarioMatched&lt;/code&gt; there. That is expected: it is not an XRechnung CIUS document. Do not relabel CII as XRechnung to force a pass. Do not treat a green local checksum as “KoSIT-valid” or “certified.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Stripe: &lt;a href="https://docs.stripe.com/invoicing/e-invoicing" rel="noopener noreferrer"&gt;Invoicing e-invoicing&lt;/a&gt; — &lt;em&gt;“doesn’t generate or transmit legally compliant e-invoice files on its own.”&lt;/em&gt; Germany page: &lt;a href="https://stripe.com/en-de/resources/more/e-invoice-in-germany" rel="noopener noreferrer"&gt;e-invoice in Germany&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;XRechnung 3.0.2 / KoSIT bundle 2026-01-31: &lt;a href="https://xeinkauf.de/xrechnung/versionen-und-bundles/" rel="noopener noreferrer"&gt;xeinkauf.de versions&lt;/a&gt;, &lt;a href="https://xeinkauf.de/aktuelles/xrechnung/xrechnung-bugfix-winter-202526/" rel="noopener noreferrer"&gt;Winter 2025/26 bugfix&lt;/a&gt;, &lt;a href="https://xeinkauf.de/app/uploads/2024/10/XRechnung-EnglishSummary-v302.pdf" rel="noopener noreferrer"&gt;English summary 3.0.2&lt;/a&gt;. Validator: KoSIT engine 1.6.3 + configuration tag &lt;code&gt;v2026-01-31&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;ZUGFeRD 2.5.2 / Factur-X 1.09.2: FeRD 4 Aug 2026; FNFE-MPE (identical standard). BMF Q7 still accepts ZUGFeRD ≥ 2.0.1 EN 16931.&lt;/li&gt;
&lt;li&gt;BMF FAQ &lt;em&gt;E-Rechnung&lt;/em&gt; (stand 23.03.2026): receive since 1 Jan 2025, e-mail inbox enough (Q8/Q12), no extra “read” duty, issue calendar Q11, Kleinunternehmer issue-exempt § 34a UStDV (Q4), structured part to archive (Q13). GoBD 2nd amendment 14 Jul 2025.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further resource (optional)
&lt;/h2&gt;

&lt;p&gt;This article is the map. If you want a packaged local Python CLI that implements it — UBL + CII emit, Stripe overlay, hash-sidecar archive, no hosted API — one implementation is &lt;a href="https://vegasweiss.gumroad.com/l/e-rechnung-kit-2026" rel="noopener noreferrer"&gt;E-Invoice Kit 2026&lt;/a&gt;. You do not need it to use the table above. Not tax or legal advice. Never invent a VAT ID.&lt;/p&gt;

</description>
      <category>stripe</category>
      <category>python</category>
      <category>einvoice</category>
      <category>germany</category>
    </item>
  </channel>
</rss>
