QR-Rechnung (Swiss QR Code): ISO 20022 Deep Dive & Automation 2026

Technische Tiefenanalyse der Schweizer QR-Rechnung (ISO 20022): QRR-Format, Structured Reference, OCR-Scanning, Bexio-Integration, Fehlerbehandlung.
Überblick
QR-Rechnung (Swiss QR Code) ist seit 30. Juni 2020 der Standard in der Schweiz.
Alte Einzahlungsscheine (ESR, oranger/roter ES) sind seit 30. September 2022 ungültig.
Technischer Standard: ISO 20022 (QRR = QR Reference, SCOR = Structured Creditor Reference).
Dieser Deep Dive erklärt:
- ✅ QR-Code-Struktur (33 Datenfelder)
- ✅ ISO 20022-Formate (pain.001, camt.053)
- ✅ OCR-Scanning & Fehlerbehandlung
- ✅ Bexio/Abacus-Integration
- ✅ Automatisierung mit Python
1. QR-Code-Struktur (33 Felder)
Swiss QR Code ist NICHT ein Standard-QR-Code (kein URL, sondern strukturierte Daten).
Format: ASCII-Text, 33 Felder, getrennt durch CRLF (Carriage Return + Line Feed, \r\n).
1.1 Pflichtfelder (11 Felder)
Beispiel-QR-Code (vereinfacht, Zeilen nummeriert):
1→ SPC (Swiss Payments Code, immer "SPC")
2→ 0200 (Version, aktuell "0200")
3→ 1 (Coding Type, immer "1" für UTF-8)
4→ CH4431999123000889012 (IBAN des Zahlungsempfängers)
5→ S (Creditor Address Type: "S" structured, "K" combined)
6→ SwissFinanceAI GmbH (Creditor Name, max. 70 Zeichen)
7→ Musterstrasse 123 (Creditor Street, max. 70 Zeichen)
8→ 8001 (Creditor Postal Code, max. 16 Zeichen)
9→ Zürich (Creditor City, max. 35 Zeichen)
10→ CH (Creditor Country, ISO 3166-1 alpha-2)
11→ (Ultimate Creditor, leer = gleich wie Creditor)
12→ (... weitere Felder, siehe unten)
1.2 Alle 33 Felder (vollständig)
Felder 1-11: Header + Creditor (siehe oben)
Felder 12-18: Amount + Currency
12→ 1200.50 (Amount, decimal mit 2 Stellen, leer = offener Betrag)
13→ CHF (Currency, "CHF" oder "EUR")
14→ (Ultimate Debtor, leer = keine Angabe)
15→ K (Debtor Address Type, "K" combined)
16→ Max Mustermann (Debtor Name)
17→ Beispielstrasse 1, 8000 Zürich (Debtor Address Line 1, bei "K")
18→ (Debtor Address Line 2, leer bei "K")
Felder 19-21: Debtor Country
19→ CH (Debtor Country)
20→ QRR (Reference Type: "QRR", "SCOR", "NON")
21→ 210000000003139471430009017 (Reference, 27 Stellen bei QRR)
Felder 22-27: Additional Information
22→ Rechnung #1234 (Unstructured Message, max. 140 Zeichen)
23→ EPD (Trailer, immer "EPD" wenn Structured Info)
24→ (Billing Information, strukturiert, leer = keine)
25→ (Reserved, leer)
26→ (Reserved, leer)
27→ (Reserved, leer)
Felder 28-33: Alternative Schemes (QR-IBAN, AV1, AV2)
28→ (Alternative Scheme 1, leer = keine)
29→ (Alternative Scheme 2, leer = keine)
30→ (Reserved, leer)
31→ (Reserved, leer)
32→ (Reserved, leer)
33→ (Reserved, leer)
Vollständiger QR-Code (als String):
SPC\r\n0200\r\n1\r\nCH4431999123000889012\r\nS\r\nSwissFinanceAI GmbH\r\nMusterstrasse 123\r\n8001\r\nZürich\r\nCH\r\n\r\n\r\n1200.50\r\nCHF\r\n\r\nK\r\nMax Mustermann\r\nBeispielstrasse 1, 8000 Zürich\r\n\r\nCH\r\nQRR\r\n210000000003139471430009017\r\nRechnung #1234\r\nEPD\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
2. QRR vs. SCOR vs. NON
3 Reference-Typen (Feld 20):
2.1 QRR (QR Reference)
Format: 27 Stellen, numerisch, inkl. Prüfziffer (Modulo 10, rekursiv).
Beispiel: 210000000003139471430009017
Struktur:
21 0000 0000 0313 9471 4300 0901 7
│ │ │
│ └── Referenz-Nummer (25 Stellen, frei wählbar)
│
└── Check Digit (Prüfziffer, Modulo 10)
Prüfziffer-Berechnung (Modulo 10, rekursiv):
def calculate_qrr_check_digit(reference: str) -> str:
"""Berechnet Prüfziffer für 26-stellige QRR-Referenz."""
table = [0, 9, 4, 6, 8, 2, 7, 1, 3, 5]
carry = 0
for digit in reference:
carry = table[(carry + int(digit)) % 10]
return str((10 - carry) % 10)
# Beispiel
ref_without_check = "21000000000313947143000901" # 26 Stellen
check_digit = calculate_qrr_check_digit(ref_without_check)
qrr_full = ref_without_check + check_digit
print(qrr_full) # 210000000003139471430009017 (27 Stellen)
Verwendung: QR-IBAN (21 Stellen, beginnt mit "30" oder "31", z.B. CH44 3199 9000 0312 3456 7).
2.2 SCOR (Structured Creditor Reference)
Format: Max. 25 Zeichen, alphanumerisch, ISO 11649.
Beispiel: RF18 5390 0754 7034 3
Struktur:
RF18 5390 0754 7034 3
│ │ │
│ │ └── Referenz-Nummer (frei wählbar)
│ └── Check Digits (ISO 7064 Mod 97-10)
│
└── "RF" (ISO 11649 Prefix)
Prüfziffer-Berechnung (ISO 7064 Mod 97-10):
def calculate_scor_check_digit(reference: str) -> str:
"""Berechnet Check Digits für SCOR-Referenz."""
# Schritt 1: Referenz + "RF00" anhängen
temp = reference + "RF00"
# Schritt 2: Buchstaben in Zahlen umwandeln (A=10, B=11, ..., Z=35)
numeric = ""
for char in temp:
if char.isdigit():
numeric += char
else:
numeric += str(ord(char) - ord('A') + 10)
# Schritt 3: Modulo 97
mod = int(numeric) % 97
check_digits = 98 - mod
return f"RF{check_digits:02d}{reference}"
# Beispiel
ref = "539007547034"
scor_full = calculate_scor_check_digit(ref)
print(scor_full) # RF18539007547034
Verwendung: Normale IBAN (nicht QR-IBAN), z.B. CH93 0900 0000 1234 5678 9.
2.3 NON (No Reference)
Format: Leer (Feld 21 ist leer).
Verwendung: Freie Zahlungen (ohne Referenz, z.B. Spenden).
Nachteil: Keine automatische Verbuchung (Buchhalter muss manuell zuordnen).
3. ISO 20022 pain.001 (Zahlung)
pain.001 = Payment Initiation (XML-Format für Zahlungen).
Verwendung: Bexio/Abacus generiert pain.001 XML → EBICS-Upload → Bank.
Beispiel (vereinfacht):
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
<CstmrCdtTrfInitn>
<!-- Header -->
<GrpHdr>
<MsgId>BEXIO-20260126-001</MsgId>
<CreDtTm>2026-01-26T14:30:00</CreDtTm>
<NbOfTxs>1</NbOfTxs>
<CtrlSum>1200.50</CtrlSum>
<InitgPty>
<Nm>SwissFinanceAI GmbH</Nm>
</InitgPty>
</GrpHdr>
<!-- Payment Information -->
<PmtInf>
<PmtInfId>PMT-001</PmtInfId>
<PmtMtd>TRF</PmtMtd> <!-- Transfer -->
<ReqdExctnDt>2026-01-26</ReqdExctnDt>
<!-- Debtor (Zahler) -->
<Dbtr>
<Nm>SwissFinanceAI GmbH</Nm>
</Dbtr>
<DbtrAcct>
<Id><IBAN>CH93 0900 0000 1234 5678 9</IBAN></Id>
</DbtrAcct>
<DbtrAgt>
<FinInstnId><BIC>POFICHBEXXX</BIC></FinInstnId> <!-- PostFinance BIC -->
</DbtrAgt>
<!-- Credit Transfer Transaction -->
<CdtTrfTxInf>
<PmtId>
<EndToEndId>E2E-001</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="CHF">1200.50</InstdAmt>
</Amt>
<!-- Creditor (Empfänger) -->
<Cdtr>
<Nm>Max Mustermann</Nm>
</Cdtr>
<CdtrAcct>
<Id><IBAN>CH44 3199 9000 0312 3456 7</IBAN></Id> <!-- QR-IBAN -->
</CdtrAcct>
<!-- QRR-Referenz -->
<RmtInf>
<Strd>
<CdtrRefInf>
<Tp><CdOrPrtry><Cd>QRR</Cd></CdOrPrtry></Tp>
<Ref>210000000003139471430009017</Ref>
</CdtrRefInf>
</Strd>
</RmtInf>
</CdtTrfTxInf>
</PmtInf>
</CstmrCdtTrfInitn>
</Document>
4. ISO 20022 camt.053 (Kontoauszug)
camt.053 = Bank to Customer Statement (Kontoauszug).
Verwendung: Bank generiert camt.053 XML → EBICS-Download → Bexio.
Beispiel (vereinfacht, QRR-Zahlung):
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.04">
<BkToCstmrStmt>
<Stmt>
<Id>STMT-20260126</Id>
<CreDtTm>2026-01-26T23:59:59</CreDtTm>
<!-- Account -->
<Acct>
<Id><IBAN>CH44 3199 9000 0312 3456 7</IBAN></Id> <!-- QR-IBAN -->
</Acct>
<!-- Balance -->
<Bal>
<Tp><CdOrPrtry><Cd>CLBD</Cd></CdOrPrtry></Tp> <!-- Closing Balance -->
<Amt Ccy="CHF">25300.50</Amt>
<CdtDbtInd>CRDT</CdtDbtInd> <!-- Credit -->
<Dt><Dt>2026-01-26</Dt></Dt>
</Bal>
<!-- Entry (Transaktion) -->
<Ntry>
<Amt Ccy="CHF">1200.50</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Sts>BOOK</Sts> <!-- Booked -->
<BookgDt><Dt>2026-01-26</Dt></BookgDt>
<ValDt><Dt>2026-01-26</Dt></ValDt>
<!-- Transaction Details -->
<NtryDtls>
<TxDtls>
<!-- QRR-Referenz -->
<RmtInf>
<Strd>
<CdtrRefInf>
<Tp><CdOrPrtry><Cd>QRR</Cd></CdOrPrtry></Tp>
<Ref>210000000003139471430009017</Ref> <!-- QRR-Referenz -->
</CdtrRefInf>
</Strd>
</RmtInf>
<!-- Debtor (Zahler) -->
<RltdPties>
<Dbtr>
<Nm>Max Mustermann</Nm>
</Dbtr>
<DbtrAcct>
<Id><IBAN>CH93 0900 0000 1234 5678 9</IBAN></Id>
</DbtrAcct>
</RltdPties>
</TxDtls>
</NtryDtls>
</Ntry>
</Stmt>
</BkToCstmrStmt>
</Document>
Bexio liest:
- QRR-Referenz:
210000000003139471430009017 - Bexio prüft: Welche Rechnung hat diese QRR-Referenz?
- Rechnung #1234 gefunden → Automatische Verbuchung (Status: "Bezahlt")
5. QR-Code-Scanning (OCR)
5.1 Python-Library: qrbill
Installation:
pip install qrbill pillow pyzbar
QR-Code scannen (von Bild):
from pyzbar.pyzbar import decode
from PIL import Image
# QR-Code von Rechnung scannen
image = Image.open("rechnung_qr.png")
decoded_objects = decode(image)
for obj in decoded_objects:
qr_data = obj.data.decode("utf-8")
print(qr_data) # SPC\r\n0200\r\n1\r\nCH44...
QR-Code parsen:
import re
def parse_swiss_qr(qr_data: str) -> dict:
"""Parst Swiss QR Code in strukturierte Daten."""
fields = qr_data.split("\r\n")
return {
"version": fields[1],
"iban": fields[3],
"creditor_name": fields[5],
"creditor_street": fields[6],
"creditor_zip": fields[7],
"creditor_city": fields[8],
"creditor_country": fields[9],
"amount": fields[11] if fields[11] else "open",
"currency": fields[12],
"debtor_name": fields[15] if len(fields) > 15 else "",
"reference_type": fields[19] if len(fields) > 19 else "",
"reference": fields[20] if len(fields) > 20 else "",
"message": fields[21] if len(fields) > 21 else ""
}
# Beispiel
qr_data = """SPC\r\n0200\r\n1\r\nCH4431999123000889012\r\nS\r\nSwissFinanceAI GmbH\r\nMusterstrasse 123\r\n8001\r\nZürich\r\nCH\r\n\r\n\r\n1200.50\r\nCHF\r\n\r\nK\r\nMax Mustermann\r\nBeispielstrasse 1, 8000 Zürich\r\n\r\nCH\r\nQRR\r\n210000000003139471430009017\r\nRechnung #1234\r\nEPD"""
parsed = parse_swiss_qr(qr_data)
print(parsed)
# {
# "version": "0200",
# "iban": "CH4431999123000889012",
# "creditor_name": "SwissFinanceAI GmbH",
# "amount": "1200.50",
# "currency": "CHF",
# "reference_type": "QRR",
# "reference": "210000000003139471430009017",
# ...
# }
5.2 QR-Code generieren
Python-Library: qrbill
Installation:
pip install qrbill
QR-Rechnung generieren:
from qrbill import QRBill
# QR-Rechnung-Daten
bill = QRBill(
account="CH4431999123000889012", # QR-IBAN
creditor={
"name": "SwissFinanceAI GmbH",
"street": "Musterstrasse 123",
"pcode": "8001",
"city": "Zürich",
"country": "CH"
},
amount=1200.50,
currency="CHF",
debtor={
"name": "Max Mustermann",
"street": "Beispielstrasse 1",
"pcode": "8000",
"city": "Zürich",
"country": "CH"
},
reference="210000000003139471430009017", # QRR
additional_information="Rechnung #1234"
)
# QR-Code als PNG generieren
bill.as_svg("qr_rechnung.svg") # Oder .as_pdf("qr_rechnung.pdf")
6. Bexio-Integration
6.1 QR-Rechnung erstellen (in Bexio)
Navigation: Bexio → Verkauf → Rechnungen → Neue Rechnung
Automatisch:
- Bexio generiert QRR-Referenz (27 Stellen) basierend auf Rechnungsnummer
- Bexio erstellt QR-Code (Swiss QR Code mit 33 Feldern)
- Bexio generiert PDF (Rechnung mit QR-Code unten rechts)
E-Mail:
- PDF-Rechnung an Kunde senden
- Kunde zahlt mit QR-Code (Banking-App scannen)
6.2 Zahlungseingang verbuchen (automatisch)
Workflow:
- Bexio ruft täglich Kontoauszug ab (EBICS HAC,
camt.053) - PostFinance sendet
camt.053XML (enthält QRR-Referenz) - Bexio parst
camt.053→ extrahiert QRR-Referenz210000000003139471430009017 - Bexio sucht Rechnung mit gleicher QRR-Referenz → Rechnung #1234 gefunden
- Bexio verbucht Zahlung automatisch (Status: "Bezahlt", Datum: 26.01.2026)
Zeitersparnis: Manuelle Verbuchung 5 Min → Automatisch 0 Min = 100% Zeitersparnis
7. Fehlerbehandlung
Fehler 1: Ungültige Prüfziffer (QRR)
Problem: QRR-Referenz hat falsche Prüfziffer.
Beispiel: 210000000003139471430009018 (letzte Ziffer falsch, sollte 7 sein).
Fehler: Bank lehnt Zahlung ab (EBICS-Fehler: INVALID_QRR_CHECK_DIGIT).
Lösung: Prüfziffer neu berechnen (siehe 2.1).
Fehler 2: IBAN-Typ stimmt nicht mit Referenz-Typ überein
Problem: QR-IBAN mit SCOR-Referenz (oder umgekehrt).
Regel:
- QR-IBAN (30xxx, 31xxx) → MUSS QRR-Referenz haben
- Normale IBAN (00xxx, 02xxx, etc.) → MUSS SCOR oder NON haben
Beispiel (falsch):
IBAN: CH44 3199 9000 0312 3456 7 (QR-IBAN, beginnt mit "31")
Reference Type: SCOR (falsch! Sollte QRR sein)
Fehler: Bank lehnt ab (EBICS-Fehler: IBAN_REFERENCE_MISMATCH).
Lösung: Referenz-Typ anpassen.
Fehler 3: QR-Code unleserlich (OCR-Fehler)
Problem: Rechnung gedruckt, QR-Code zu klein/verpixelt.
Mindestgröße: 46 × 46 mm (gemäß SIX-Standard).
Lösung: QR-Code in höherer Auflösung drucken (300 DPI).
8. ROI-Kalkulation (QR-Rechnung-Automation)
Manueller Prozess (100 Rechnungen/Monat):
- Rechnung erstellen: 5 Min
- Zahlungseingang kontrollieren: 3 Min (täglich E-Banking checken)
- Zahlung verbuchen: 5 Min (in Bexio manuell erfassen)
- GESAMT: 13 Min/Rechnung = 1.300 Min/Monat = 21,7h/Monat
Automatisierter Prozess (Bexio + EBICS + QR-Rechnung):
- Rechnung erstellen: 1 Min (Bexio generiert QR-Code automatisch)
- Zahlungseingang kontrollieren: 0 Min (Bexio importiert täglich)
- Zahlung verbuchen: 0 Min (automatisch via QRR-Referenz)
- GESAMT: 1 Min/Rechnung = 100 Min/Monat = 1,7h/Monat
Einsparung: 21,7h - 1,7h = 20h/Monat = 240h/Jahr
Kosten:
- Bexio Professional: CHF 30/Monat × 12 = CHF 360
- PostFinance EBICS: CHF 20/Monat × 12 = CHF 240
- GESAMT: CHF 600/Jahr
Einsparungen:
- Zeitersparnis: 240h × CHF 85/h = CHF 20.400/Jahr
ROI: CHF 20.400 - CHF 600 = CHF 19.800 Gewinn (3.300% ROI) 🚀
Nächste Schritte
Option 1: QR-Rechnung-Automation-Service (CHF 490, 6h)
- Wir richten Bexio + EBICS + QR-Rechnung für Sie ein
- Inklusive: QR-IBAN-Beantragung, Testzahlung, Schulung
Option 2: Custom QR-Code-Integration (CHF 1.500, 10h)
- Wir entwickeln Custom-QR-Code-Generator/Parser für Ihr System
- Inklusive: Python-Library, OCR-Scanning, Fehlerbehandlung
Veröffentlicht: 26. Januar 2026 Autor: SwissFinanceAI Team Kategorie: Payment Standards
References
Transparency Notice: This article may contain AI-assisted content. All citations link to verified sources. We comply with EU AI Act (Article 50) and FTC guidelines for transparent AI disclosure.


