{
  "openapi": "3.1.0",
  "info": {
    "title": "eRechio API",
    "version": "1.3.0",
    "summary": "E-Rechnungen (XRechnung UBL/CII, ZUGFeRD-/Factur-X-XML) mit den KoSIT-Regeln prüfen, Fehler auf Deutsch erklärt.",
    "description": "Prüft eine E-Rechnung gegen das XML-Schema (XSD: UBL 2.1 bzw. UN/CEFACT CII D16B) und mit denselben Schematron-Regeln und Szenarien wie die Prüfkonfiguration der KoSIT für XRechnung 3.0.2 (EN 16931 für UBL Invoice, UBL CreditNote und CII sowie die nationalen Regeln BR-DE). Jede Meldung trägt Regelcode, Fehlerstufe, Fundstelle und – für die häufigsten Regeln – eine deutsche Erklärung mit Hinweis zur Behebung.\n\nErgebnis in zwei Stufen: `regelpruefung_bestanden` (keine Fehler in den Schematron-Regeln, Spezifikationskennung passt zu einem KoSIT-Szenario) und `vollstaendig_validiert` (zusätzlich schemagültig – das entspricht der Annahme durch das KoSIT-Prüftool). Nicht geprüft wird die inhaltliche und steuerliche Richtigkeit. Keine PDF-Annahme (bei ZUGFeRD das eingebettete XML senden).\n\nÄnderungen 1.3.0 (2026-10-23): `GET /v1/status` meldet den echten Zustand – `ok` (200) nur mit bereitem Prüfprozess, lesbaren Schlüsseln und speicherbaren Nutzungsdaten, sonst `gestört` (503) mit `gruende`; Prüfungen werden dann mit 503 `gestoert` abgelehnt und nicht gezählt. Gezählt wird erst, wenn die Antwort 200 vollständig gesendet ist. Trennt der Client die Verbindung, wird die Prüfung beendet (auch in der Warteschlange) und nicht gezählt.\n\nWichtig: HTTP 200 heißt „Prüfung ausgeführt“, nicht „Rechnung fehlerfrei“. Maßgeblich sind `vollstaendig_validiert` und `regelpruefung_bestanden`.\n\nÄnderungen 1.2.0 (2026-10-22): neues Feld `regelstand` in Prüfergebnis und Status – Kennung der verwendeten Regel- und Schemadateien (Anfang ihrer SHA-256); Herkunft, Prüfsummen und Änderungsprotokoll des Prüfverhaltens auf https://erechio.de/aenderungen.html.\n\nÄnderungen 1.1.0 (2026-10-21): XSD-Schemaprüfung ergänzt; neue Felder `vollstaendig_validiert`, `regelpruefung_bestanden`, `schemapruefung`; `valid` ist veraltet und gleich `vollstaendig_validiert` (in 1.0.0 war `valid` schon bei bestandener Regelprüfung ohne Schemaprüfung `true`); `ohne` nennt jetzt die inhaltliche Prüfung; Kontingent wird vor der Prüfung reserviert und nur bei 200 gezählt; neu Status 503 (`zeitlimit`, `ausgelastet`); Meldungen mit Code `XSD` (Schemafehler, Fundstelle als Zeile) und `ABBRUCH` (Regelprüfung wegen eines Werts im falschen Format abgebrochen). Änderungsprotokoll: https://erechio.de/api/#aenderungen\n\nDie Rechnung wird nur im Arbeitsspeicher geprüft und nicht gespeichert. Die Basisadresse steht in der Mail mit Ihrem Schlüssel. Testschlüssel kostenlos (50 Dokumente im Monat), Starter 500 Dokumente im Monat für 14 € inkl. 19 % MwSt. (netto 11,76 €). Nur für Unternehmer (§ 14 BGB) mit Sitz in Deutschland. Eine Verfügbarkeit wird nicht zugesagt.\n\nTechnische Hinweise zum Datenformat, keine Steuer- oder Rechtsberatung. eRechio ist kein Angebot der KoSIT.",
    "termsOfService": "https://erechio.de/agb.html",
    "contact": {
      "name": "eRechio",
      "url": "https://erechio.de/api/",
      "email": "info@erechio.de"
    },
    "x-logo": {
      "url": "https://erechio.de/logo.svg"
    }
  },
  "externalDocs": {
    "description": "Dokumentation mit Beispielen",
    "url": "https://erechio.de/api/"
  },
  "servers": [
    {
      "url": "{ERECHIO_URL}",
      "description": "eRechio API (Nürnberg)",
      "variables": {
        "ERECHIO_URL": {
          "default": "https://api.erechio.de",
          "description": "Basisadresse der API"
        }
      }
    }
  ],
  "tags": [
    {
      "name": "Prüfen",
      "description": "E-Rechnung prüfen"
    },
    {
      "name": "Status",
      "description": "Zustand des Dienstes"
    }
  ],
  "paths": {
    "/v1/validate": {
      "post": {
        "tags": [
          "Prüfen"
        ],
        "operationId": "validateInvoice",
        "summary": "E-Rechnung prüfen",
        "description": "Rechnung als XML im Body, höchstens 2 MB. DOCTYPE- und ENTITY-Deklarationen werden abgelehnt. Zählt ein Dokument im Monatskontingent nur, wenn die Antwort 200 gesendet wurde. Das Kontingent wird vor der Prüfung reserviert, gleichzeitige Anfragen können es also nicht überschreiten. Abgelehnte (400/413/422), abgebrochene (503, getrennte Verbindung) und fehlgeschlagene (500) Prüfungen zählen nicht.",
        "security": [
          {
            "bearer": []
          },
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "description": "XRechnung (UBL Invoice, UBL CreditNote oder CII) bzw. das XML einer ZUGFeRD-/Factur-X-Rechnung.",
          "content": {
            "application/xml": {
              "schema": {
                "type": "string",
                "maxLength": 2097152
              }
            },
            "text/xml": {
              "schema": {
                "type": "string",
                "maxLength": 2097152
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Prüfung ausgeführt – das heißt nicht „Rechnung fehlerfrei“. Das Ergebnis steht in `vollstaendig_validiert` (maßgeblich für die Annahme), `regelpruefung_bestanden`, `schemapruefung` und `meldungen`. Gezählt wird die Prüfung, wenn diese Antwort vollständig gesendet ist.",
            "headers": {
              "X-Kontingent-Rest": {
                "description": "Verbleibende Dokumente im laufenden Monat",
                "required": true,
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ergebnis"
                },
                "example": {
                  "vollstaendig_validiert": false,
                  "regelpruefung_bestanden": false,
                  "schemapruefung": "bestanden",
                  "valid": false,
                  "syntax": "UBL",
                  "spezifikation": "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0",
                  "szenario": "EN16931 XRechnung (UBL Invoice)",
                  "geprueft": [
                    "XML-Schema (UBL 2.1)",
                    "EN 16931 (UBL)",
                    "XRechnung 3.0 (BR-DE)"
                  ],
                  "fehler": 1,
                  "warnungen": 0,
                  "meldungen": [
                    {
                      "code": "BR-DE-15",
                      "level": "fehler",
                      "text": "Das Element \"Buyer reference\" (BT-10 (Käuferreferenz (bei Behörden: Leitweg-ID))) muss übermittelt werden.",
                      "location": "/Invoice",
                      "erklaerung": {
                        "titel": "Käuferreferenz (Leitweg-ID) fehlt",
                        "was": "XRechnung verlangt in jeder Rechnung eine Käuferreferenz (BT-10). …",
                        "beheben": "Tragen Sie die Referenz ein, die Ihr Kunde Ihnen vorgibt: …",
                        "pfad": "cbc:BuyerReference",
                        "mehr": "https://erechio.de/fehler/br-de-15.html"
                      }
                    }
                  ],
                  "kontingent": {
                    "genutzt": 1,
                    "limit": 500,
                    "rest": 499
                  },
                  "regeln": "KoSIT XRechnung 3.0.2, EN 16931 Schematron 1.3.16, XSD UBL 2.1 / CII D16B",
                  "regelstand": "e17455c9cb03",
                  "ohne": "Inhaltliche und steuerliche Richtigkeit der Angaben",
                  "dauer_ms": 396
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Fehler400"
          },
          "401": {
            "$ref": "#/components/responses/Fehler401"
          },
          "405": {
            "$ref": "#/components/responses/Fehler405"
          },
          "413": {
            "$ref": "#/components/responses/Fehler413"
          },
          "422": {
            "$ref": "#/components/responses/Fehler422"
          },
          "429": {
            "$ref": "#/components/responses/Fehler429"
          },
          "500": {
            "$ref": "#/components/responses/Fehler500"
          },
          "503": {
            "$ref": "#/components/responses/Fehler503"
          }
        }
      }
    },
    "/v1/status": {
      "get": {
        "tags": [
          "Status"
        ],
        "operationId": "getStatus",
        "summary": "Zustand des Dienstes",
        "description": "Ohne Schlüssel. Version, Regelstand und Bereitschaft (seit 1.3.0 ehrlich: 503, wenn keine Prüfung möglich ist).",
        "security": [],
        "responses": {
          "200": {
            "description": "Dienst läuft",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                },
                "example": {
                  "status": "ok",
                  "version": "1.3.0",
                  "regeln": "KoSIT XRechnung 3.0.2, EN 16931 Schematron 1.3.16, XSD UBL 2.1 / CII D16B",
                  "regelstand": "e17455c9cb03",
                  "zeit": "2026-10-17T08:00:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Dienst gestört: keine Prüfungen möglich (z. B. kein Prüfprozess bereit, Nutzungsdaten nicht lesbar oder nicht speicherbar). Prüfungen werden in diesem Zustand mit 503 `gestoert` abgelehnt und nicht gezählt.",
            "headers": {
              "Retry-After": {
                "required": true,
                "description": "Sekunden bis zum nächsten Versuch",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                },
                "example": {
                  "status": "gestört",
                  "gruende": [
                    "Nutzungsdaten nicht speicherbar"
                  ],
                  "version": "1.3.0",
                  "regeln": "KoSIT XRechnung 3.0.2, EN 16931 Schematron 1.3.16, XSD UBL 2.1 / CII D16B",
                  "regelstand": "e17455c9cb03",
                  "zeit": "2026-10-23T08:00:00.000Z"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Header `Authorization: Bearer pk_…`"
      },
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Alternativ zum Bearer-Header"
      }
    },
    "schemas": {
      "Ergebnis": {
        "type": "object",
        "required": [
          "vollstaendig_validiert",
          "regelpruefung_bestanden",
          "schemapruefung",
          "valid",
          "syntax",
          "spezifikation",
          "geprueft",
          "fehler",
          "warnungen",
          "meldungen",
          "kontingent",
          "regeln",
          "regelstand",
          "ohne",
          "dauer_ms"
        ],
        "properties": {
          "vollstaendig_validiert": {
            "type": "boolean",
            "description": "`true` nur, wenn die Rechnung schemagültig ist (XSD) und die Regelprüfung bestanden hat – entspricht der Annahme durch das KoSIT-Prüftool. Sagt nichts über die inhaltliche oder steuerliche Richtigkeit."
          },
          "regelpruefung_bestanden": {
            "type": "boolean",
            "description": "`true`, wenn die Schematron-Regeln (EN 16931, bei XRechnung BR-DE) keinen Fehler melden und die Spezifikationskennung (BT-24) zu einem KoSIT-Szenario passt. Allein noch keine vollständige Validierung."
          },
          "schemapruefung": {
            "type": "string",
            "enum": [
              "bestanden",
              "fehlgeschlagen"
            ],
            "description": "Ergebnis der XSD-Schemaprüfung (UBL 2.1 bzw. CII D16B). Schemafehler stehen in `meldungen` mit Code `XSD`."
          },
          "valid": {
            "type": "boolean",
            "deprecated": true,
            "description": "Veraltet seit 1.1.0, gleich `vollstaendig_validiert`. In 1.0.0 war `valid` schon ohne Schemaprüfung `true`."
          },
          "syntax": {
            "type": "string",
            "enum": [
              "UBL",
              "CII"
            ]
          },
          "spezifikation": {
            "type": [
              "string",
              "null"
            ],
            "description": "Spezifikationskennung BT-24 aus der Rechnung"
          },
          "szenario": {
            "type": [
              "string",
              "null"
            ],
            "description": "Gewähltes KoSIT-Szenario; fehlt, wenn keins passt"
          },
          "hinweis": {
            "type": "string",
            "description": "Nur gesetzt, wenn kein KoSIT-Szenario passt (dann nur EN 16931 geprüft)"
          },
          "geprueft": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Angewandte Regelwerke"
          },
          "fehler": {
            "type": "integer",
            "minimum": 0
          },
          "warnungen": {
            "type": "integer",
            "minimum": 0
          },
          "leitweg_id": {
            "$ref": "#/components/schemas/LeitwegId"
          },
          "meldungen": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Meldung"
            }
          },
          "kontingent": {
            "$ref": "#/components/schemas/Kontingent"
          },
          "regeln": {
            "type": "string",
            "description": "Regelstand"
          },
          "regelstand": {
            "type": "string",
            "pattern": "^[0-9a-f]{12}$",
            "description": "Kennung des Regelstands: Anfang der SHA-256 über alle Regel- und Schemadateien. Gleiche Kennung = gleiche Regeln. Details: https://erechio.de/aenderungen.html (seit 1.2.0)"
          },
          "ohne": {
            "type": "string",
            "description": "Was nicht geprüft wird"
          },
          "dauer_ms": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "Meldung": {
        "type": "object",
        "required": [
          "code",
          "level",
          "text"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Regelcode, z. B. BR-DE-15; `XSD` für Schemafehler, `ABBRUCH`, wenn die Regelprüfung wegen eines Werts im falschen Format abbrach",
            "examples": [
              "BR-DE-15"
            ]
          },
          "level": {
            "type": "string",
            "enum": [
              "fehler",
              "warnung",
              "hinweis"
            ]
          },
          "text": {
            "type": "string",
            "description": "Meldungstext mit deutschen BT-/BG-Namen"
          },
          "location": {
            "type": [
              "string",
              "null"
            ],
            "description": "XPath der Fundstelle; bei Schemafehlern „Zeile n“"
          },
          "erklaerung": {
            "$ref": "#/components/schemas/Erklaerung"
          }
        }
      },
      "Erklaerung": {
        "type": "object",
        "description": "Deutsche Erklärung; nur für Regeln, zu denen es eine ausführliche Erklärung gibt",
        "required": [
          "titel",
          "was",
          "beheben",
          "mehr"
        ],
        "properties": {
          "titel": {
            "type": "string"
          },
          "was": {
            "type": "string",
            "description": "Was die Regel verlangt"
          },
          "beheben": {
            "type": "string",
            "description": "Wie man den Fehler behebt"
          },
          "pfad": {
            "type": [
              "string",
              "null"
            ],
            "description": "Element in der jeweiligen Syntax (UBL oder CII)"
          },
          "mehr": {
            "type": "string",
            "format": "uri",
            "description": "Ausführliche Seite zum Regelcode"
          }
        }
      },
      "LeitwegId": {
        "type": "object",
        "description": "Nur gesetzt, wenn BT-10 wie eine Leitweg-ID aussieht. Hinweis, ändert das KoSIT-Ergebnis nicht.",
        "required": [
          "wert",
          "pruefziffer_ok"
        ],
        "properties": {
          "wert": {
            "type": "string"
          },
          "pruefziffer_ok": {
            "type": "boolean",
            "description": "Prüfziffer nach ISO 7064 Mod 97-10"
          },
          "erwartet": {
            "type": "string",
            "description": "Richtige Prüfziffer, nur wenn `pruefziffer_ok` false ist"
          }
        }
      },
      "Kontingent": {
        "type": "object",
        "required": [
          "genutzt",
          "limit",
          "rest"
        ],
        "properties": {
          "genutzt": {
            "type": "integer",
            "minimum": 0
          },
          "limit": {
            "type": "integer",
            "minimum": 0
          },
          "rest": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "Status": {
        "type": "object",
        "required": [
          "status",
          "version",
          "regeln",
          "regelstand",
          "zeit"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "gestört"
            ],
            "description": "ok = bereit für Prüfungen; gestört = keine Prüfungen möglich (Grund in gruende), HTTP 503"
          },
          "version": {
            "type": "string",
            "description": "Version der API, z. B. 1.3.0"
          },
          "regeln": {
            "type": "string"
          },
          "regelstand": {
            "type": "string",
            "pattern": "^[0-9a-f]{12}$",
            "description": "Kennung des Regelstands: Anfang der SHA-256 über alle Regel- und Schemadateien. Gleiche Kennung = gleiche Regeln. Details: https://erechio.de/aenderungen.html (seit 1.2.0)"
          },
          "zeit": {
            "type": "string",
            "format": "date-time"
          },
          "gruende": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Nur bei gestört: Gründe ohne interne Details (seit 1.3.0)"
          }
        }
      },
      "Fehler": {
        "type": "object",
        "required": [
          "fehler"
        ],
        "properties": {
          "fehler": {
            "type": "object",
            "required": [
              "code",
              "text"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "kein_xml",
                  "dtd",
                  "schluessel",
                  "methode",
                  "zu_gross",
                  "kein_format",
                  "xml_fehler",
                  "rate",
                  "kontingent",
                  "nicht_gefunden",
                  "intern",
                  "zeitlimit",
                  "ausgelastet",
                  "gestoert"
                ]
              },
              "text": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "responses": {
      "Fehler400": {
        "description": "Body ist kein XML (`kein_xml`) oder enthält DOCTYPE-/ENTITY-Deklarationen (`dtd`)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Fehler"
            }
          }
        }
      },
      "Fehler401": {
        "description": "API-Schlüssel fehlt oder ist ungültig (`schluessel`)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Fehler"
            }
          }
        }
      },
      "Fehler405": {
        "description": "Falsche Methode (`methode`), nur POST",
        "headers": {
          "Allow": {
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Fehler"
            }
          }
        }
      },
      "Fehler413": {
        "description": "Rechnung größer als 2 MB (`zu_gross`)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Fehler"
            }
          }
        }
      },
      "Fehler422": {
        "description": "Kein E-Rechnungsformat (`kein_format`) oder XML nicht wohlgeformt (`xml_fehler`)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Fehler"
            }
          }
        }
      },
      "Fehler429": {
        "description": "Mehr als 60 Prüfungen pro Minute (`rate`, mit `Retry-After`) oder Monatskontingent erreicht (`kontingent`; laufende Prüfungen sind eingerechnet)",
        "headers": {
          "Retry-After": {
            "description": "Sekunden bis zum nächsten Versuch, nur bei `rate`",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Fehler"
            }
          }
        }
      },
      "Fehler500": {
        "description": "Interner Fehler (`intern`); die Rechnung wurde nicht gespeichert",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Fehler"
            }
          }
        }
      },
      "Fehler503": {
        "description": "Keine Prüfung: Zeitlimit überschritten (`zeitlimit`), Dienst ausgelastet (`ausgelastet`) oder gestört (`gestoert`, siehe `GET /v1/status`). Zählt nicht im Kontingent.",
        "headers": {
          "Retry-After": {
            "required": true,
            "description": "Sekunden bis zum nächsten Versuch",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Fehler"
            }
          }
        }
      }
    }
  }
}
