Skip to main content

Swiss QR bill generation library for Python

Project description

chqr

Swiss QR-bill generation library for Python

PyPI version License

Example Swiss QR-bill generated with chqr

Overview

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.

Key Features

  • 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

Installation

Install chqr from PyPI using pip:

pip install chqr

Or using uv:

uv add chqr

Quick Start

Here'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.

Usage Examples

Basic QR-bill with Debtor Information

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")

Different Reference Types

The library supports all three reference types defined in the Swiss QR-bill standard.

QRR: QR Reference

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
)

SCOR: Creditor Reference (ISO 11649)

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
)

NON: No Reference

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!",
)

Optional Features

Additional Information and Billing Data

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",
)

Alternative Payment Procedures

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"],
)

Multilingual Support

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")

Notification Payment

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
)

API Reference

QRBill

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.00 for notification). Can be None for 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.

Creditor

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.

UltimateDebtor

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,
)

ValidationError

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}")

Reference Types Explained

Understanding when to use each reference type is crucial for generating valid QR-bills.

QRR (QR Reference)

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

SCOR (Creditor Reference)

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

NON (No Reference)

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.

Development

Setup

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 install

Running Tests

The 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 -v

Code Quality

Code 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 --fix

Pre-commit hooks automatically run these checks before each commit.

License

This project is licensed under the ISC License. See the LICENSE file for details.

Links & Resources


Made with ❤️ by Gil Balsiger in Switzerland

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chqr-1.2.3.tar.gz (14.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chqr-1.2.3-py3-none-any.whl (17.6 kB view details)

Uploaded Python 3

File details

Details for the file chqr-1.2.3.tar.gz.

File metadata

  • Download URL: chqr-1.2.3.tar.gz
  • Upload date:
  • Size: 14.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.24 {"installer":{"name":"uv","version":"0.9.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for chqr-1.2.3.tar.gz
Algorithm Hash digest
SHA256 90c97896c1414b4e53434f3fc8cf9328153b980aa5fcfa52af8a77b6661d6ab9
MD5 c64c6292cb81ace2990c34b6064a106a
BLAKE2b-256 a9b9f3d02210e5a8779f75c3d784d55261ae0d98282c4274410fc9a894c718ef

See more details on using hashes here.

File details

Details for the file chqr-1.2.3-py3-none-any.whl.

File metadata

  • Download URL: chqr-1.2.3-py3-none-any.whl
  • Upload date:
  • Size: 17.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.24 {"installer":{"name":"uv","version":"0.9.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for chqr-1.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 55efff391c66418a63a8491099a2190bab2eda0782d8b0208cd4e26cafa63a80
MD5 7a5d274f10ad2f6322827554e77ab606
BLAKE2b-256 d6451982cc44ec4da395f1448d2d02a27cacee893f01cb71fb14b754dfcf25c9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page