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

By SwissFinanceAI Team
|
|16 Min Read
QR-Rechnung (Swiss QR Code): ISO 20022 Deep Dive & Automation 2026
Image: SwissFinanceAI / banking

Technische Tiefenanalyse der Schweizer QR-Rechnung (ISO 20022): QRR-Format, Structured Reference, OCR-Scanning, Bexio-Integration, Fehlerbehandlung.

QR-RechnungSwiss QR CodeISO 20022QRRPain.001Camt.053

Ü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:

  1. QRR-Referenz: 210000000003139471430009017
  2. Bexio prüft: Welche Rechnung hat diese QRR-Referenz?
  3. 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:

  1. Bexio generiert QRR-Referenz (27 Stellen) basierend auf Rechnungsnummer
  2. Bexio erstellt QR-Code (Swiss QR Code mit 33 Feldern)
  3. 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:

  1. Bexio ruft täglich Kontoauszug ab (EBICS HAC, camt.053)
  2. PostFinance sendet camt.053 XML (enthält QRR-Referenz)
  3. Bexio parst camt.053 → extrahiert QRR-Referenz 210000000003139471430009017
  4. Bexio sucht Rechnung mit gleicher QRR-Referenz → Rechnung #1234 gefunden
  5. 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

👉 Service buchen

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

👉 Service buchen


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.

    blog.relatedArticles

    Wir schützen Ihre Privatsphäre

    Wir verwenden Cookies, um Ihr Erlebnis zu verbessern. Mit "Akzeptieren" stimmen Sie der Verwendung zu.