Zum Inhalt springen
Invoapi

Quickstart & Rezepte

Fünf vollständige Beispiele. Jedes wurde vor der Veröffentlichung gegen die laufende API ausgeführt — die gezeigten Antworten sind die echten, Beträge und Kennungen unverändert, base64-Inhalte gekürzt.

Bevor Sie anfangen

Basis-URL
https://api.invoapi.de
Anmeldung
Authorization: Bearer inv_live_… — alternativ der Header X-API-Key. Schlüssel erstellen Sie im Dashboard.
Ohne Schlüssel
/api/v1/health/api/v1/formats/api/v1/formats/{id}
Bei Rückfragen
Jede Antwort trägt X-Request-ID. Schicken Sie die Kennung mit — damit finden wir genau Ihren Aufruf im Protokoll.

1Gültiges ZUGFeRD-PDF aus JSON erzeugen

Ein hybrides PDF/A-3 (Factur-X) mit eingebettetem XML, in derselben Anfrage geprüft. Der häufigste Einstieg.

Anfrage
curl -X POST https://api.invoapi.de/api/v1/generate \
  -H "Authorization: Bearer $INVOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "format": "zugferd",
    "syntax": "cii",
    "profile": "en16931",
    "output": "pdf",
    "validate": true,
    "invoice": {
      "invoice_number": "RE-2026-0100",
      "issue_date": "2026-08-23",
      "due_date": "2026-09-22",
      "currency": "EUR",
      "buyer_reference": "04011000-12345-34",
      "delivery": { "date": "2026-08-23" },
      "seller": {
        "name": "Muster GmbH", "street": "Musterstraße 1",
        "postal_code": "10115", "city": "Berlin", "country_code": "DE",
        "vat_id": "DE123456789", "email": "rechnung@muster.de",
        "contact": {
          "name": "Erika Muster", "phone": "+49 30 1234567",
          "email": "rechnung@muster.de"
        }
      },
      "buyer": {
        "name": "Beispiel AG", "street": "Teststraße 10",
        "postal_code": "20095", "city": "Hamburg", "country_code": "DE",
        "vat_id": "DE987654321", "email": "kreditor@beispiel.de"
      },
      "items": [
        { "name": "Softwareentwicklung", "quantity": 12,
          "unit": "HUR", "unit_price": 110, "vat_rate": 19 }
      ],
      "payment": {
        "means_code": "58", "iban": "DE02120300000000202051",
        "terms": "Zahlbar innerhalb von 30 Tagen ohne Abzug."
      }
    }
  }'
Antwort 200
{
  "success": true,
  "format": "zugferd", "syntax": "cii", "version": "2.5.2", "profile": "en16931",
  "valid": true,
  "invoice_id": "RE-2026-0100",
  "totals": {
    "net": "1320.00", "tax": "250.80",
    "gross": "1570.80", "payable": "1570.80", "currency": "EUR"
  },
  "validation": {
    "status": "valid",
    "rule_sets": [
      { "name": "XML Schema for UN/CEFACT XML (SCRDM - CII uncoupled)",
        "kind": "xml-schema", "passed": true },
      { "name": "Schematron rules for EN16931 (CII)",
        "kind": "schematron", "passed": true },
      { "name": "PDF/A-3 conformance (veraPDF)",
        "kind": "pdf-a", "passed": true },
      { "name": "ZUGFeRD / Factur-X profile rules (Mustang)",
        "kind": "schematron", "passed": true }
    ]
  },
  "document": {
    "mime_type": "application/pdf",
    "filename": "RE-2026-0100.pdf",
    "content_base64": "JVBERi0xLjQK…"
  }
}

Das PDF kommt als base64 in content_base64 — nicht als Binärdatei. In der Shell: `… | jq -r .document.content_base64 | base64 -d > rechnung.pdf`. Der PDF/A-Schritt prüft den Container, nicht nur das XML.

2Eine vorhandene Datei prüfen

Vier Wege, dasselbe Ergebnis. Nimm den, der zu deinem HTTP-Client passt — alle vier sind gleichwertig.

Anfrage
# 1 — Datei-Upload
curl -X POST https://api.invoapi.de/api/v1/validate \
  -H "Authorization: Bearer $INVOAPI_KEY" \
  -F "file=@rechnung.xml;type=application/xml"

# 2 — rohes XML im Body
curl -X POST https://api.invoapi.de/api/v1/validate \
  -H "Authorization: Bearer $INVOAPI_KEY" \
  -H "Content-Type: application/xml" \
  --data-binary @rechnung.xml

# 3 — JSON mit eingebettetem XML
curl -X POST https://api.invoapi.de/api/v1/validate \
  -H "Authorization: Bearer $INVOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"xml": "<Invoice …>"}'

# 4 — JSON mit base64 (auch für PDFs)
curl -X POST https://api.invoapi.de/api/v1/validate \
  -H "Authorization: Bearer $INVOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content_base64": "PD94bWwg…"}'
Antwort 200
{
  "status": "invalid",
  "valid": false,
  "detected_format": "xrechnung",
  "syntax": "ubl",
  "result": {
    "summary": { "errors": 1, "warnings": 0, "infos": 1, "rules_checked": null },
    "issues": [
      {
        "severity": "error",
        "rule": "BR-DE-6",
        "message": "Das Element \"Seller contact telephone number\" (BT-42) muss übermittelt werden.",
        "explanation": "Eine XRechnung-spezifische Regel (deutsche Verschärfung von EN 16931).",
        "suggestion": "Setzen Sie seller.contact.phone.",
        "field": "seller.contact.phone",
        "business_term": "BT-42",
        "rule_set": "Schematron rules for Invoice - CIUS XRechnung (UBL)"
      }
    ]
  },
  "request_id": "req_…"
}

Jeder Befund trägt neben der Regel-ID auch explanation, suggestion und field — du brauchst keine eigene Übersetzungstabelle für KoSIT-Regeln.

3XRechnung in ZUGFeRD umwandeln

convert nimmt eine Quelle (content_base64, xml oder kanonisches invoice) und ein Ziel (xml, json, html, pdf).

Anfrage
curl -X POST https://api.invoapi.de/api/v1/convert \
  -H "Authorization: Bearer $INVOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content_base64": "'"$(base64 -i rechnung-xrechnung.xml)"'",
    "target": "pdf",
    "format": "zugferd"
  }'
Antwort 200
{
  "success": true,
  "source": { "format": "xrechnung", "syntax": "ubl" },
  "target": "pdf",
  "format": "zugferd",
  "document": {
    "mime_type": "application/pdf",
    "filename": "RE-2026-0042.pdf",
    "content_base64": "JVBERi0xLjQK…"
  }
}

Für target: "xml" und "pdf" ist format erforderlich — es sagt, in welchen Standard umgewandelt wird. Für "json" und "html" ist es optional.

4Format erkennen und Inhalt auslesen

Zwei leichte Endpunkte ohne Validierung: detect sagt, was ein Dokument ist; parse liest es in das kanonische Modell.

Anfrage
# Was ist das überhaupt?
curl -X POST https://api.invoapi.de/api/v1/detect \
  -H "Authorization: Bearer $INVOAPI_KEY" \
  -F "file=@unbekannt.pdf;type=application/pdf"

# Inhalt als JSON herauslesen
curl -X POST https://api.invoapi.de/api/v1/parse \
  -H "Authorization: Bearer $INVOAPI_KEY" \
  -H "Content-Type: application/xml" \
  --data-binary @rechnung.xml
Antwort 200
{
  "format": "zugferd",
  "syntax": "cii",
  "version": "2.5.2",
  "profile": "en16931",
  "container": "pdf",
  "document_type": "invoice",
  "confidence": 1.0,
  "evidence": [
    "CustomizationID (BT-24) is 'urn:cen.eu:en16931:2017'",
    "factur-x.xml found as an embedded file"
  ]
}

Ein unbekanntes Dokument liefert format: "unknown" mit confidence: 0.0 — niemals eine geratene Zuordnung.

5Summen prüfen, ohne ein Dokument zu erzeugen

calculate rechnet Netto, Steueraufschlüsselung und Bruttobetrag aus, ohne etwas zu erzeugen. Nützlich, um die eigene Berechnung gegenzuprüfen.

Anfrage
curl -X POST https://api.invoapi.de/api/v1/calculate \
  -H "Authorization: Bearer $INVOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "invoice": {
      "invoice_number": "RE-1", "issue_date": "2026-08-23", "currency": "EUR",
      "seller": { "name": "Muster GmbH", "street": "Musterstraße 1",
                  "postal_code": "10115", "city": "Berlin",
                  "country_code": "DE", "vat_id": "DE123456789" },
      "buyer":  { "name": "Beispiel AG", "street": "Teststraße 10",
                  "postal_code": "20095", "city": "Hamburg", "country_code": "DE" },
      "items": [
        { "name": "Beratung", "quantity": 10, "unit": "HUR",
          "unit_price": 100, "vat_rate": 19 },
        { "name": "Handbuch", "quantity": 3, "unit": "C62",
          "unit_price": 24.5, "vat_rate": 7 }
      ]
    }
  }'
Antwort 200
{
  "totals": {
    "net": "1073.50", "tax": "195.15",
    "gross": "1268.65", "payable": "1268.65", "currency": "EUR"
  },
  "breakdown": [
    { "category": "S", "rate": "19.00",
      "taxable_amount": "1000.00", "tax_amount": "190.00" },
    { "category": "S", "rate": "7.00",
      "taxable_amount": "73.50", "tax_amount": "5.15" }
  ],
  "warnings": [],
  "request_id": "req_…"
}

Gerundet wird kaufmännisch und je Steuergruppe: 73,50 € × 7 % = 5,145 € wird zu 5,15 €, nicht zu 5,14 €.

Gut zu wissen

Welcher Endpunkt nimmt was entgegen

Endpunktakzeptiert
validate · detect · parse · rendermultipart/form-data (Feld file) · rohes application/xml · application/pdf · text/plain · JSON mit xml, content_base64 oder invoice
generate · convert · calculateJSON

Aufruf aus dem Browser

Geht nicht, und das ist Absicht: Die API setzt für fremde Domains keine CORS-Header, ein fetch von einer Webseite scheitert daher. Der Grund ist Ihr API-Schlüssel — was der Browser senden kann, kann ein Besucher im Quelltext lesen. Rufen Sie die API aus Ihrem Backend auf.

Grenzen

  • Dokumente bis 10 MiB; darüber 413.
  • Jede Antwort trägt X-RateLimit-Limit, X-RateLimit-Remaining und X-RateLimit-Reset (Fensterlänge in Sekunden). Bei Überschreitung 429 mit Retry-After.
  • Ein Rumpf ohne Content-Type wird mit 415 abgelehnt — er lässt sich nicht lesen.

Fehler sehen immer gleich aus

Fehlerformat
{
  "error": {
    "code": "BAD_REQUEST",
    "message": "…",
    "details": [ { "field": "…", "rule": "…", "message": "…" } ],
    "request_id": "req_…"
  }
}

ubl und cii sind Syntaxen, keine eigenen Standards

Ein damit erzeugtes Dokument trägt als CustomizationID (BT-24) die EN-16931-Kennung — denn das ist der Standard, den es erfüllt. detect meldet es deshalb als en16931. Das ist kein Rundlauf-Fehler: Die Syntax bestimmt die XML-Grammatik, der Standard die Regeln.

Welche Formate und Fähigkeiten aktuell unterstützt werden, fragen Sie live unter GET /api/v1/formats ab — nichts davon muss fest verdrahtet werden. Die vollständige Referenz steht in der Dokumentation.