The Swiss QR-bill is the standardized payment slip used throughout Switzerland and Liechtenstein. It combines a machine-readable Swiss QR Code with human-readable payment information, making it easy for individuals and businesses to process payments efficiently.
chqr is a Python library that generates compliant Swiss QR-bills in SVG format. It handles all the complexity of the Swiss QR-bill specification v2.3, including data validation, QR code generation, and proper formatting. The library ensures your generated bills meet the official standards valid from November 21, 2025.
- Full compliance with Swiss QR-bill specification v2.3 (November 2025)
- Complete validation of all input data (IBANs, references, amounts, addresses)
- SVG generation with multilingual support (English, German, French, Italian)
- Support for all reference types: QRR (QR Reference), SCOR (Creditor Reference), and NON (no reference)
- Type-safe API with comprehensive error messages
- Zero configuration - works out of the box with sensible defaults
Install chqr from PyPI using pip:
pip install chqrOr using uv:
uv add chqrHere's a minimal example to generate your first Swiss QR-bill:
from decimal import Decimal
from chqr import QRBill, Creditor
# Define the creditor (who receives the payment)
creditor = Creditor(
name="Max Muster & Söhne",
street="Musterstrasse",
building_number="123",
postal_code="8000",
city="Seldwyla",
country="CH",
)
# Create the QR-bill
bill = QRBill(
account="CH4431999123000889012", # QR-IBAN
creditor=creditor,
amount=Decimal("1949.75"),
currency="CHF",
reference_type="QRR",
reference="210000000003139471430009017",
)
# Generate SVG
svg_content = bill.generate_svg(language="en")
# Save to file
with open("qr_bill.svg", "w", encoding="utf-8") as f:
f.write(svg_content)This generates a complete Swiss QR-bill as an SVG file, ready to be printed or included in invoices.
Including debtor (payer) information pre-fills the payment slip for your customers:
from decimal import Decimal
from chqr import QRBill, Creditor, UltimateDebtor
creditor = Creditor(
name="Furniture AG",
street="Industriestrasse",
building_number="45",
postal_code="3007",
city="Bern",
country="CH",
)
debtor = UltimateDebtor(
name="Anna Müller",
street="Hauptstrasse",
building_number="12",
postal_code="8001",
city="Zürich",
country="CH",
)
bill = QRBill(
account="CH5800791123000889012",
creditor=creditor,
debtor=debtor,
amount=Decimal("550.00"),
currency="CHF",
reference_type="SCOR",
reference="RF18539007547034",
additional_information="Invoice #2024-0156",
)
svg = bill.generate_svg(language="de")The library supports all three reference types defined in the Swiss QR-bill standard.
QR References are 27-digit numeric references that can only be used with QR-IBANs (IBANs with IID in range 30000-31999):
bill = QRBill(
account="CH4431999123000889012", # QR-IBAN (IID: 31999)
creditor=creditor,
amount=Decimal("250.00"),
currency="CHF",
reference_type="QRR",
reference="210000000003139471430009017", # 27 digits with check digit
)Creditor References are alphanumeric references that must be used with regular IBANs:
bill = QRBill(
account="CH5800791123000889012", # Regular IBAN
creditor=creditor,
amount=Decimal("180.50"),
currency="CHF",
reference_type="SCOR",
reference="RF720191230100405JSH0438", # ISO 11649 format
)When no structured reference is needed, use the NON type with regular IBANs:
bill = QRBill(
account="CH5800791123000889012", # Regular IBAN
creditor=creditor,
amount=Decimal("75.00"),
currency="EUR",
reference_type="NON",
additional_information="Donation - Thank you!",
)You can include unstructured messages and structured billing information:
bill = QRBill(
account="CH5800791123000889012",
creditor=creditor,
amount=Decimal("1200.00"),
currency="CHF",
reference_type="SCOR",
reference="RF18539007547034",
additional_information="Order #2024-0891 from 15.10.2024",
billing_information="//S1/10/10201409/11/201021/30/102673386",
)Support for alternative payment methods like eBill:
bill = QRBill(
account="CH5800791123000889012",
creditor=creditor,
amount=Decimal("450.00"),
currency="CHF",
reference_type="SCOR",
reference="RF18539007547034",
alternative_procedures=["eBill/B/customer@example.com"],
)Generate QR-bills in any of the four official Swiss languages:
# German
svg_de = bill.generate_svg(language="de")
# French
svg_fr = bill.generate_svg(language="fr")
# Italian
svg_it = bill.generate_svg(language="it")
# English (default)
svg_en = bill.generate_svg(language="en")You can generate QR-bills with a zero amount for notification purposes (e.g., eBill enrollment). This automatically adds the required "DO NOT USE FOR PAYMENT" text (or its translation) to the bill.
bill = QRBill(
account="CH5800791123000889012",
creditor=creditor,
amount=Decimal("0.00"), # Triggers notification mode
currency="CHF",
# "DO NOT USE FOR PAYMENT" is automatically added to additional_information
)The main class for creating Swiss QR-bills.
QRBill(
account: str,
creditor: Creditor,
currency: str,
amount: Decimal | None = None,
reference_type: str = "NON",
reference: str | None = None,
additional_information: str | None = None,
debtor: UltimateDebtor | None = None,
billing_information: str | None = None,
alternative_procedures: list[str] | None = None,
)Parameters:
- account (str): IBAN or QR-IBAN, exactly 21 characters. Must be from Switzerland (CH) or Liechtenstein (LI).
- creditor (Creditor): Creditor information (who receives the payment).
- currency (str): Payment currency, either
"CHF"or"EUR". - amount (Decimal | None): Payment amount with exactly 2 decimal places. Range: 0.01 to 999,999,999.99 (or
0.00for notification). Can beNonefor open amounts. - reference_type (str): Reference type -
"QRR","SCOR", or"NON". Default:"NON". - reference (str | None): Payment reference. Required for QRR and SCOR types.
- additional_information (str | None): Unstructured message, max 140 characters.
- debtor (UltimateDebtor | None): Ultimate debtor (payer) information.
- billing_information (str | None): Structured billing information, max 140 characters.
- alternative_procedures (list[str] | None): Alternative payment methods, max 2 items of 100 characters each.
Methods:
- generate_svg(language: str = "en") → str: Generate SVG representation. Language can be
"en","de","fr", or"it". - generate_qr_code() → segno.QRCode: Generate the QR code object.
- build_data_string() → str: Build the raw QR code data string.
Represents the creditor (invoice issuer) information.
Creditor(
name: str,
postal_code: str,
city: str,
country: str,
street: str | None = None,
building_number: str | None = None,
)Parameters:
- name (str): Creditor name or company, max 70 characters.
- postal_code (str): Postal code, max 16 characters, without country prefix.
- city (str): City/town name, max 35 characters.
- country (str): Two-character ISO 3166-1 country code (e.g.,
"CH"). - street (str | None): Street name or P.O. Box, max 70 characters.
- building_number (str | None): Building number, max 16 characters.
Represents the ultimate debtor (payer) information. Has identical parameters to Creditor.
UltimateDebtor(
name: str,
postal_code: str,
city: str,
country: str,
street: str | None = None,
building_number: str | None = None,
)Exception raised when input data fails validation. All validation happens during QRBill initialization, providing immediate feedback with clear error messages.
from chqr import ValidationError
try:
bill = QRBill(...)
except ValidationError as e:
print(f"Validation failed: {e}")Understanding when to use each reference type is crucial for generating valid QR-bills.
The QR Reference is a 27-digit numeric reference with a built-in check digit. It can only be used with QR-IBANs, which are special IBANs with an Institution Identifier (IID) in the range 30000-31999.
When to use: You have a QR-IBAN from your bank and need systematic payment reconciliation with a unique numeric reference.
Format: Exactly 27 numeric digits, where the last digit is a Modulo 10 recursive check digit.
Example: 210000000003139471430009017
The Creditor Reference follows the ISO 11649 standard and is an alphanumeric reference. It must be used with regular IBANs (not QR-IBANs).
When to use: You have a regular IBAN and want to use a structured reference for payment reconciliation.
Format: Starts with "RF" followed by 2 check digits and 1-21 alphanumeric characters.
Example: RF720191230100405JSH0438
No structured reference is used. This must be used with regular IBANs (not QR-IBANs).
When to use: No specific payment reference is needed, such as for donations or simple payments where additional information is sufficient.
Format: The reference field remains empty, but you can use additional_information for unstructured messages.
This project uses uv for dependency management:
# Clone the repository
git clone https://github.com/balsigergil/chqr.git
cd chqr
# Install dependencies
uv sync
# Install pre-commit hooks
uv run pre-commit installThe project follows Test-Driven Development (TDD) practices with comprehensive test coverage:
# Run all tests
uv run pytest
# Run with coverage report
uv run pytest --cov=chqr
# Run specific test file
uv run pytest tests/test_qr_bill.py
# Verbose output
uv run pytest -vCode formatting and linting is handled by Ruff:
# Format code
uv run ruff format
# Check code
uv run ruff check
# Auto-fix issues
uv run ruff check --fixPre-commit hooks automatically run these checks before each commit.
This project is licensed under the ISC License. See the LICENSE file for details.
- PyPI Package: https://pypi.org/project/chqr/
- Swiss QR-bill Specification: SIX Payment Standards
- Official Implementation Guidelines: See
assets/ig-qr-bill-v2.3-en.pdf
