Der schnellste Weg von einem Sandbox-Schlüssel zu einer ausgestellten E-Rechnung: Kunde anlegen, Rechnung erstellen und ausstellen, XRechnung und ZUGFeRD abholen — mit echten curl-Beispielen.

Dieser Quickstart führt dich einmal komplett durch die Fortlauf E-Rechnung API: Kunde anlegen, Rechnung als Entwurf erstellen, ausstellen — und die fertige XRechnung (CII) sowie das hybride ZUGFeRD/Factur-X-PDF abholen, das die KoSIT-Validierung besteht. Alles über echte HTTP-Aufrufe, kein SDK nötig.

Basis-URL: ein einziger Token

Jedes Beispiel unten liest die Basis-URL aus einem Wert. Setz ihn einmal als Umgebungsvariable, dann laufen alle folgenden Aufrufe dagegen — nichts sonst in den Beispielen kennt den Host.

Basis-URL (ein Token)
# Aktuelle Basis-URL dieser Doku:
#   https://api.fortlauf.de/v1
#
# Öffentliche Aufrufe laufen über das API-Gateway unter dem /v1-Präfix;
# das Gateway entfernt /v1, bevor es an den Dienst weiterreicht.
export FORTLAUF_API_BASE="https://api.fortlauf.de/v1"

1. Sandbox-Schlüssel holen

API-Schlüssel werden im Kontobereich ausgestellt (die Schlüsselverwaltung akzeptiert selbst keine API-Schlüssel — sie läuft über deinen eingeloggten Account). Lege im Kontobereich unter Entwickler → API-Schlüssel einen Schlüssel im Test-Modus an. Ein Test-Schlüssel beginnt mit sk_test_, ein Live-Schlüssel mit sk_live_ — das Präfix legt den Modus dauerhaft fest. Test-Daten sind vollständig von Live-Daten isoliert.

Der volle Schlüssel wird genau einmal angezeigt. Leg ihn in eine Umgebungsvariable, dann gelten alle folgenden Aufrufe für ihn:

bash
export FORTLAUF_API_KEY="sk_test_dein_sandbox_schluessel"

Der Schlüssel trägt Mandant, Entität und Modus in sich — du musst weder X-Tenant-Id noch X-Dashboard-Mode mitschicken. Jeder Aufruf braucht nur den Authorization: Bearer-Header.

Einmalige Voraussetzung: das Absenderprofil. Ausstellen (Schritt 5) prüft die Pflichtangaben zum Rechnungssteller. Fehlen Name, Anschrift, Ort, PLZ, Land oder USt-IdNr/Steuernummer, bricht der Aufruf mit 422 ab — noch bevor deine Rechnungsdaten geprüft werden. Hinterleg das Profil einmal im Rechnungsbereich unter Rechnungseinstellungen oder per PUT /settings/company; danach gilt es für alle weiteren Rechnungen.

2. Kunde anlegen

Master-Daten des Rechnungsempfängers. name ist Pflicht; die Kundennummer (customerNumber, z. B. K-00001) vergibt der Server. Der optionale Idempotency-Key-Header macht ein wiederholtes Anlegen zum Replay statt zum Duplikat.

POST /customers
curl -sS -X POST "$FORTLAUF_API_BASE/customers" \
  -H "Authorization: Bearer $FORTLAUF_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: quickstart-kunde-1" \
  -d '{
        "name": "Achsfeld Transporte GmbH",
        "addressLine1": "Gewerbestraße 8",
        "postalCode": "59192",
        "city": "Bergkamen",
        "countryCode": "DE",
        "vatId": "DE245817096",
        "email": "rechnung@achsfeld.de"
      }'

Antwort (201 Created) — merk dir die id für den nächsten Schritt:

json
{
"id": "8f14e45f-ceea-4e0b-9c9a-1b2c3d4e5f60",
"customerNumber": "K-00001",
"name": "Achsfeld Transporte GmbH",
"city": "Bergkamen",
"countryCode": "DE",
"mode": "test"
}

3. Rechnung als Entwurf erstellen

Eine Rechnung wird zuerst als Entwurf (draft) erstellt. Summen und Steuer rechnet immer der Server — schick keine Totals mit, sie werden ignoriert. Beträge und Mengen sind Dezimal-Strings (z. B. "1500.00"), um exakte Genauigkeit zu wahren. unitCode ist ein UN/ECE-Rec-20-Einheitencode (C62 = Stück, HUR = Stunde).

POST /invoices
curl -sS -X POST "$FORTLAUF_API_BASE/invoices" \
  -H "Authorization: Bearer $FORTLAUF_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: quickstart-rechnung-1" \
  -d '{
        "currency": "EUR",
        "customerId": "8f14e45f-ceea-4e0b-9c9a-1b2c3d4e5f60",
        "buyer": {
          "name": "Achsfeld Transporte GmbH",
          "addressLine1": "Gewerbestraße 8",
          "postalCode": "59192",
          "city": "Bergkamen",
          "countryCode": "DE",
          "vatId": "DE245817096"
        },
        "buyerReference": "PO-2026-0042",
        "lineItems": [
          {
            "description": "API-Integration (Beratung)",
            "quantity": "10",
            "unitCode": "HUR",
            "unitPriceNet": "150.00",
            "taxRatePercent": "19"
          }
        ]
      }'

Antwort (201 Created): Status draft, Summen serverseitig berechnet, noch keine Rechnungsnummer (die vergibt erst das Ausstellen).

json
{
"id": "c56a4180-65aa-42ec-a945-5fd21dec0538",
"status": "draft",
"currency": "EUR",
"totals": { "totalNet": "1500.00", "totalTax": "285.00", "totalGross": "1785.00" }
}

4. (Optional) Vorab prüfen — ohne Nummer zu verbrauchen

Bevor du ausstellst, kannst du denselben KoSIT-Preflight als Trockenlauf laufen lassen. Er verbraucht keine Rechnungsnummer und ändert den Entwurf nicht — ideal, um fehlende Pflichtangaben früh zu sehen (inkl. der beratenden §14-Zusammenfassung, section14).

POST /invoices/{id}/validate
curl -sS -X POST "$FORTLAUF_API_BASE/invoices/c56a4180-65aa-42ec-a945-5fd21dec0538/validate" \
  -H "Authorization: Bearer $FORTLAUF_API_KEY"

5. Rechnung ausstellen

PATCH …/finalize schaltet draft → issued: vergibt die Rechnungsnummer atomar, rendert und validiert XRechnung und ZUGFeRD parallel gegen die KoSIT-Regeln und legt Artefakte samt Validierungsbericht ab. Die Antwort enthält eine validation-Zusammenfassung mit dem Verdikt.

PATCH /invoices/{id}/finalize
curl -sS -X PATCH "$FORTLAUF_API_BASE/invoices/c56a4180-65aa-42ec-a945-5fd21dec0538/finalize" \
  -H "Authorization: Bearer $FORTLAUF_API_KEY"

Antwort (200 OK): jetzt issued, mit Nummer und Validierungs-Verdikt.

json
{
"id": "c56a4180-65aa-42ec-a945-5fd21dec0538",
"status": "issued",
"invoiceNumber": "RE-2026-00001",
"validation": { "verdict": "pass" },
"section14": { "status": "passed" }
}

6. ZUGFeRD/Factur-X abholen

Beim Ausstellen entsteht das hybride ZUGFeRD/Factur-X-PDF (PDF/A-3b) — das strukturierte EN-16931-CII-XML steckt darin eingebettet, du brauchst also keine zweite Datei:

GET /invoices/{id}/pdf
# ZUGFeRD/Factur-X (PDF/A-3b, CII-XML eingebettet)
curl -sS "$FORTLAUF_API_BASE/invoices/c56a4180-65aa-42ec-a945-5fd21dec0538/pdf" \
  -H "Authorization: Bearer $FORTLAUF_API_KEY" \
  -o rechnung.pdf

Eine separate XRechnung (CII, XML) erzeugt Fortlauf für Behördenrechnungen. Dafür legst du die Rechnung mit "documentTarget": "b2g" an und hinterlegst die Leitweg-ID — dann steht sie unter GET /invoices/{id}/xml bereit. Siehe XRechnung per API erzeugen.

7. (Optional) Validierungsbericht abholen

Der beim Ausstellen erzeugte KoSIT-Validierungsbericht ist dauerhaft abrufbar — Grundlage für deinen Compliance-Nachweis:

GET /invoices/{id}/validation-reports
curl -sS "$FORTLAUF_API_BASE/invoices/c56a4180-65aa-42ec-a945-5fd21dec0538/validation-reports" \
  -H "Authorization: Bearer $FORTLAUF_API_KEY"

Das war der komplette Weg: Sandbox-Schlüssel → Kunde → Entwurf → ausgestellt → XRechnung und ZUGFeRD in der Hand. Für Modi und Schlüssel im Detail siehe Authentifizierung und Sandbox.