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
  • 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 for faster installation:

uv pip install 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")

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

Work in Progress

The following features are currently under development and will be available in future releases:

Additional Output Formats

While SVG generation is fully supported, we're working on adding more output formats to make the library even more versatile:

  • PDF Generation: Direct PDF output for seamless integration into invoicing systems and document workflows
  • PNG Export: Raster image export for use in contexts where vector graphics aren't supported

These formats will follow the same API pattern as generate_svg(), making it easy to switch between output types based on your needs.

Optional Bill Variants

  • Bill without a specified amount, allowing payers to enter their own amount
  • Bill without a specified debtor, suitable for donation scenarios

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.1.1.tar.gz (13.8 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.1.1-py3-none-any.whl (16.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: chqr-1.1.1.tar.gz
  • Upload date:
  • Size: 13.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","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.1.1.tar.gz
Algorithm Hash digest
SHA256 ae1f6da053b7e303ebd9aa247488021cc5489f510d6b421321c34640f736b015
MD5 942957de07ef70c65bdf8be42a5af4bd
BLAKE2b-256 5f580e5097943d821521dafc8df560f37c7460f492e7a39d8135188c92144a08

See more details on using hashes here.

File details

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

File metadata

  • Download URL: chqr-1.1.1-py3-none-any.whl
  • Upload date:
  • Size: 16.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","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.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f2eab62c00dd196b6bc6dd4a2822757434d968c3f40db8ca77e1150841b9f25c
MD5 f055dad25f61e5e7007469279a291817
BLAKE2b-256 41fcb4399596affb1b131082b60e330a03b06be8520ddf7a509671062406c96f

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