Zum Inhalt springen

Aktualisiert

GiroCode auf der Rechnung: der Standard und die Fallstricke

Was in einem GiroCode (EPC-QR-Code) steht, Feld für Feld nach EPC069-12, welche Grenzen gelten — und warum so viele erzeugte Codes an einer Prüfziffer, einem Komma oder einem Umlaut scheitern.

Das Quadrat unten auf einer Rechnung, das die Banking-App scannt und daraus die Überweisung ausfüllt, heißt in Deutschland GiroCode. Es ist kein Produkt einer Bank, sondern ein offener Standard: der EPC-QR-Code des European Payments Council, beschrieben im Dokument EPC069-12, Quick Response Code: Guidelines to Enable Data Capture for the Initiation of a SEPA Credit Transfer. Lizenzfrei, und kurz genug, um ihn an einem Nachmittag zu lesen.

Wir haben ihn diese Woche zweimal gelesen: einmal für einen GiroCode-Generator, der vollständig im Browser läuft, und einmal, als der dafür geschriebene Prüfer unsere eigenen Beispielrechnungen ablehnte. Darum geht es unten auch.

Zwölf Zeilen Text

Ein GiroCode enthält keinen Link und keine Kennung, nur bis zu zwölf Zeilen reinen Text, getrennt durch Zeilenumbrüche. Die App liest sie und füllt ihr Überweisungsformular; bestätigen muss der Zahler dort selbst.

Zeile Inhalt Grenze nach EPC069-12
1 Service-Tag BCD fest
2 Version 001 oder 002 ab 002 ist die BIC innerhalb des EWR optional
3 Zeichensatz, 1 bis 8 1 steht für UTF-8
4 Kennung SCT (SEPA Credit Transfer) fest
5 BIC 8 oder 11 Zeichen
6 Name des Empfängers höchstens 70 Zeichen
7 IBAN höchstens 34 Zeichen, nur IBAN
8 Betrag, EUR gefolgt von der Zahl EUR0.01 bis EUR999999999.99, optional
9 Zweck-Code (AT-T007) höchstens 4 Zeichen, optional
10 strukturierte Referenz höchstens 35 Zeichen, optional
11 unstrukturierter Verwendungszweck höchstens 140 Zeichen, optional
12 Hinweis an den Zahler höchstens 70 Zeichen, optional

Dazu kommen drei Regeln, die über einzelne Zeilen hinausgehen: Zeile 10 und Zeile 11 schließen sich gegenseitig aus, hinter der letzten gefüllten Zeile folgt kein Zeilenumbruch mehr, und der ganze Inhalt darf 331 Bytes nicht überschreiten.

Woran erzeugte Codes scheitern

Keiner der folgenden Fehler fällt beim Erzeugen auf. Die meisten Bibliotheken kodieren, was man ihnen gibt, und das Ergebnis ist ein einwandfreier QR-Code mit einem Inhalt, den eine App, die sich an den Standard hält, nicht übernehmen kann. Bemerkt wird das erst beim Zahler — nachdem er die Rechnung gescannt hat.

Die Prüfziffer der IBAN

Die beiden Ziffern hinter dem Ländercode einer IBAN sind eine Prüfsumme über den Rest, gerechnet nach ISO 7064 Mod 97-10: die ersten vier Zeichen ans Ende stellen, Buchstaben in Zahlen umsetzen (A = 10 bis Z = 35), und das Ganze muss modulo 97 den Rest 1 ergeben.

Für Musterdaten nimmt man üblicherweise eine IBAN aus lauter Nullen, DE00 0000 0000 0000 0000 00. Die kann es nicht geben: 00 ist nie eine gültige Prüfziffer. Für eine deutsche Kontonummer aus lauter Nullen ist die richtige 36, also DE36 0000 0000 0000 0000 00 — weiterhin niemandes Konto, aber gültig.

Wir haben das auf die unangenehme Art gelernt: Unsere eigene Beispielrechnung und unsere Beispielmahnung trugen seit Wochen DE00… im GiroCode. Erst der Prüfer, den wir für den Generator schrieben, hat sie abgelehnt. Beide sind inzwischen korrigiert.

Wer die Prüfung selbst einbaut, stolpert noch über etwas anderes: Die umgestellte Zahl hat je nach Land 20 bis über 30 Stellen, bei einer deutschen IBAN 24, und liegt damit weit über den rund 16 Stellen, die eine Gleitkommazahl genau darstellt. % 97 auf die ganze Zahl liefert still ein falsches Ergebnis; gerechnet wird Ziffer für Ziffer.

const umgestellt = iban.slice(4) + iban.slice(0, 4);
const ziffern = [...umgestellt]
  .map((c) => (c >= 'A' && c <= 'Z' ? c.charCodeAt(0) - 55 : c))
  .join('');
let rest = 0;
for (const d of ziffern) rest = (rest * 10 + Number(d)) % 97;
return rest === 1;

Das Komma im Betrag

Zeile 8 verlangt einen Punkt als Dezimaltrenner: EUR1234.50. Wer den Betrag mit einer deutschen Zahlformatierung erzeugt, schreibt EUR1234,50 — lesbar für Menschen, aber kein Betrag im Sinne des Standards. Der Fehler entsteht meist nicht im GiroCode-Code selbst, sondern eine Schicht darüber, wo jemand den Betrag für die Anzeige formatiert und denselben String weiterreicht.

Strukturiert oder frei

Zeile 10 ist die strukturierte Gläubigerreferenz; der Standard nennt dafür die RF-Referenz nach ISO 11649, die mit RF und zwei Prüfziffern beginnt. Eine Rechnungsnummer wie 2026-0042 ist keine solche Referenz, und eine Banking-App, die das Feld als strukturiert behandelt, kann damit nichts anfangen. Die Rechnungsnummer gehört als Verwendungszweck in Zeile 11. Beide Zeilen zu füllen ist nicht erlaubt, und welche davon eine Bibliothek dann verwirft, ist ihre Sache, nicht die des Standards.

Auch hier waren unsere Beispiele betroffen: Sie trugen die Rechnungsnummer in Zeile 10, obwohl die Mahnung sie in ihrer eigenen Bildunterschrift „Verwendungszweck“ nannte.

331 Bytes, nicht Zeichen

Die Grenze ist in Bytes angegeben, und in UTF-8 kostet ein Umlaut zwei davon. Ein Verwendungszweck von 140 Zeichen, der die Feldgrenze einhält, kann mit genug ä, ö und ü die Gesamtgrenze reißen.

Die Zahl selbst ist kein Zufall: Der Standard legt Fehlerkorrektur-Stufe M fest und erlaubt höchstens QR-Version 13, 69 × 69 Module. Genau 331 Bytes passen in einen solchen Code.

Der erklärte und der tatsächliche Zeichensatz

Zeile 3 erklärt, wie der Rest kodiert ist. Erklärt ein Code 1 (UTF-8), schreibt den Text aber in ISO 8859-1, erscheinen Umlaute im Empfängernamen als Zeichensalat. Der Code ist dann nicht ungültig, nur falsch — was schlimmer ist, weil es niemand prüft.

In der Vorlage

In einer Formfeed-Vorlage entsteht der GiroCode aus den Daten der Rechnung, mit dem Helper epcQr. So steht er in unserer Beispielrechnung, die der Render-Server ausgibt:

<img src="{{ epcQr({
  name: company.name,
  iban: company.iban,
  bic: company.bic,
  amount: net + vat,
  text: 'Rechnung ' ~ invoice.number
}, { size: 110 }) }}" alt="GiroCode">

Der Betrag kommt aus derselben Rechnung wie die Summe darüber, die Rechnungsnummer als Verwendungszweck in Zeile 11. Wie Liquid und Handlebars den Aufruf schreiben, zeigt die Helper-Referenz. Die Felder sind in allen dreien dieselben: text füllt Zeile 11, und reference gehört nur zu einer RF-Gläubigerreferenz.

Die Beispielrechnung, wie sie der Render-Server ausgibt, mit dem GiroCode unten links

Was der Helper tut und was nicht: epcQr baut die Zeilen nach dem Standard und zeichnet den Code, mit Fehlerkorrektur M. Er prüft die Daten beim Rendern nicht; das tut der Generator, der dieselben Zeilen aus demselben Code baut und vorher die Prüfziffer, die Längen, den Betragsbereich und die 331 Bytes kontrolliert. Wer seine Stammdaten einmal dort einfügt, sieht, ob der Code auf der nächsten Rechnung stimmt.

Was ein GiroCode nicht ist

Er ist eine Überweisung und nichts sonst: keine Lastschrift, keine zweite Währung, keine Zahlungsaufforderung, die ohne den Zahler etwas auslöst. Und er ist keine E-Rechnung. ZUGFeRD, Factur-X und XRechnung machen die Rechnung selbst maschinenlesbar für die Buchhaltung des Empfängers; der GiroCode hilft einem Menschen beim Bezahlen. Beides passt auf dieselbe Rechnung.

Der Standard und die Angaben zu den Feldern wurden am 21. September 2026 gegen EPC069-12 in Version 3.1 (19. März 2024) geprüft.

Philipp Staudt

Heute mit dem Rendern beginnen

Der kostenlose Plan enthält 100 Einheiten im Monat und kostenlose Testrenderings. Wechseln Sie den Plan, wenn Sie mehr brauchen.