Dokumentation

Ein vollständiges Beispiel

Alles von den vorigen Seiten zusammen: die Felder auf einen Blick, eine vollständige Rechnung zum Kopieren und Ausführen, und der Beweis, dass die Datei, die dabei entsteht, gültig ist - geprüft auf Ihrem eigenen Rechner. Sie fürchten, das sei kompliziert? Sehen Sie, wie kurz es ist.

Die Felder auf einen Blick

Sie brauchen das Wesentliche. Alles andere ergänzen Sie nur, wenn Ihr Fall es verlangt.

Immer

FeldNötig?
number, issueDate, currencyJa
seller - name + address (country)Ja
buyer - name + address (country)Ja
lines - mindestens eine (name, quantity, unit, netUnitPrice, vat)Ja
seller.vatIdJa, wenn Sie Umsatzsteuer berechnen

Optional - nach Bedarf

FeldWas es ergänzt
dueDate, payment (iban, terms)Zahlungsangaben
notes, purchaseOrderRef, contractRefReferenzen
allowancesChargesNachlässe und Zuschläge auf den Beleg
paidAmount, payeeName, delivery, typealles Weitere

XRechnung (deutsches B2G) verlangt zusätzlich

FeldWas es ist
buyerReferencedie Leitweg-ID
seller / buyer .electronicAddresselektronische Adressen
seller.contact (name, phone, email)ein erreichbarer Kontakt
dueDate oder payment.terms, dazu payment.ibanFälligkeit und Zahlungsweg

Fehlt einer XRechnung etwas davon, nennt Ihnen die Bibliothek das Feld - siehe Prüfung.

Eine vollständige Rechnung

Kopieren Sie das in rechnung.ts, führen Sie npx tsx rechnung.ts aus, und Sie erhalten rechnung.pdf und rechnung.xml.

import { writeFileSync } from "node:fs";
import { renderZugferd, type Invoice } from "@jasy/e-invoice";

const rechnung: Invoice = {
  number: "RE-001",
  issueDate: "2026-06-21",
  currency: "EUR",
  dueDate: "2026-07-05",
  purchaseOrderRef: "PO-7782",
  notes: ["Vielen Dank für Ihren Auftrag."],
  seller: {
    name: "Northwind GmbH",
    vatId: "DE265013614",
    address: { line1: "Hauptstraße 1", city: "Berlin", postCode: "10115", country: "DE" },
    contact: { name: "A. Schmidt", email: "rechnung@northwind.de", phone: "+49 30 123456" },
  },
  buyer: {
    name: "Globex AG",
    address: { line1: "Marktplatz 5", city: "München", postCode: "80331", country: "DE" },
  },
  lines: [
    {
      name: "Beratung",
      description: "Workshop vor Ort",
      quantity: 8,
      unit: "HUR",
      netUnitPrice: 120,
      vat: { category: "S", ratePercent: 19 },
    },
    {
      name: "Lizenz",
      quantity: 1,
      unit: "C62",
      netUnitPrice: 480,
      vat: { category: "S", ratePercent: 19 },
    },
  ],
  allowancesCharges: [
    {
      isCharge: false,
      amount: 50,
      reason: "Treuerabatt",
      vat: { category: "S", ratePercent: 19 },
    },
    { isCharge: true, amount: 12, reason: "Versand", vat: { category: "S", ratePercent: 19 } },
  ],
  payment: {
    iban: "DE89370400440532013000",
    bic: "COBADEFFXXX",
    accountName: "Northwind GmbH",
    terms: "Zahlbar innerhalb von 14 Tagen ohne Abzug.",
  },
};

async function build() {
  const { bytes, xml } = await renderZugferd(rechnung); // das Layout spricht von Haus aus Deutsch
  writeFileSync("rechnung.pdf", bytes); // das ZUGFeRD-PDF/A-3
  writeFileSync("rechnung.xml", xml); // das EN-16931-CII-XML
}

build();

Jede Summe wird für Sie berechnet: das Netto (1.402,00), die 19 % Umsatzsteuer (266,38) und das Brutto (1.668,38) ergeben sich aus den Positionen, dem Rabatt und dem Zuschlag - Sie addieren nie selbst.

Prüfen

Jetzt der Beweis. Nichts wird hochgeladen - die Prüfung läuft auf Ihrem Rechner:

npx @jasy/cli validate ./rechnung.pdf
  rechnung.pdf  ·  ZUGFeRD · EN 16931 (CII)

  EN 16931 rules      ✓ valid
  PDF/A-3 structure   ✓ 13/13
  PDF/A (veraPDF)     ✓ compliant

  → VALID

Das ist der ganze Ablauf: Sie haben die Rechnung beschrieben, die Bibliothek hat PDF und XML gebaut und gerechnet, und dasselbe Prüfprogramm, das ein Finanzamt verwendet, hat es bestätigt - auf Ihrem Rechner. Erzeugen, prüfen, fertig.