Skip to content

Python SDK

Official Python SDK for thelawin.dev.

Requires Python 3.9+

Installation

Beta-Phase

Während der Beta sind die SDKs über GitHub verfügbar. PyPI-Veröffentlichung folgt mit dem stabilen Release.

bash
# Via GitHub
pip install git+https://github.com/steviee/thelawin-clients.git#subdirectory=python

# Oder in requirements.txt
thelawin @ git+https://github.com/steviee/thelawin-clients.git#subdirectory=python

Quick Start

python
from thelawin import ThelawinClient

client = ThelawinClient(api_key="env_sandbox_xxx")

result = (client.invoice()
    .number("2026-001")
    .date("2026-01-15")
    .seller(name="Acme GmbH", vat_id="DE123456789", city="Berlin", country="DE")
    .buyer(name="Customer AG", city="München", country="DE")
    .add_item(description="Consulting Services", quantity=8, unit="HUR", unit_price=150, vat_rate=19)
    .template("minimal")
    .generate())

if result.success:
    result.save_pdf("./invoice.pdf")
    print(f"Generated: {result.filename}")
else:
    for error in result.errors:
        print(f"{error.path}: {error.message}")

Async Support

python
from thelawin import AsyncThelawinClient

async with AsyncThelawinClient(api_key="env_sandbox_xxx") as client:
    result = await (client.invoice()
        .number("2026-001")
        .date("2026-01-15")
        .seller(name="Acme GmbH", vat_id="DE123456789", city="Berlin", country="DE")
        .buyer(name="Customer AG", city="München", country="DE")
        .add_item(description="Consulting", quantity=8, unit="HUR", unit_price=150, vat_rate=19)
        .generate())

    if result.success:
        await result.save_pdf_async("./invoice.pdf")

Client Options

python
client = ThelawinClient(
    api_key="env_sandbox_xxx",
    base_url="https://api.thelawin.dev",  # optional
    timeout=30.0                          # optional, seconds
)

Builder API

Invoice Details

python
client.invoice()
    .number("2026-001")           # Required
    .date("2026-01-15")           # Required, str or date
    .due_date("2026-02-15")       # Optional
    .currency("EUR")              # Default: "EUR"

Parties

python
.seller(
    name="Acme GmbH",            # Required
    vat_id="DE123456789",        # Required
    street="Hauptstraße 1",
    city="Berlin",               # Required
    postal_code="10115",
    country="DE"                 # Required
)
.buyer(
    name="Customer AG",          # Required
    vat_id="DE987654321",
    city="München",              # Required
    country="DE"                 # Required
)

Line Items

python
.add_item(
    description="Consulting",    # Required
    quantity=8,                  # Required
    unit="HUR",                  # Required
    unit_price=150.00,           # Required
    vat_rate=19.0                # Required
)

Customization

python
.template("minimal")            # "minimal", "classic", "compact"
.locale("de")                   # "en", "de", "fr", "es", "it"
.accent_color("#8b5cf6")
.footer_text("Thank you!")
python
# From file (auto Base64)
.logo_file("./logo.png")
.logo_file("./logo.png", width_mm=30)

# From Base64
.logo_base64("iVBORw0KGgo...", width_mm=30)

Result Handling

python
result = builder.generate()

if result.success:
    print(result.filename)       # "invoice-2026-001.pdf"
    print(result.validation)     # ValidationResult(status="valid", ...)

    # Save to file
    result.save_pdf("./invoice.pdf")

    # Get bytes
    pdf_bytes = result.to_bytes()

    # Get data URL
    data_url = result.to_data_url()
else:
    for error in result.errors:
        print(f"{error.path}: {error.message}")

Error Handling

python
from thelawin import (
    ThelawinApiError,
    ThelawinNetworkError,
    ThelawinQuotaExceededError
)

try:
    result = client.invoice().generate()
except ThelawinQuotaExceededError:
    print("Quota exceeded, upgrade your plan")
except ThelawinNetworkError as e:
    print(f"Network error: {e}")
except ThelawinApiError as e:
    print(f"API error {e.status_code}: {e.message}")

Type Hints

Full type hints are included for IDE autocomplete:

python
from thelawin import InvoiceResult, InvoiceSuccess, InvoiceFailure, ValidationError

def handle_result(result: InvoiceResult) -> None:
    if isinstance(result, InvoiceSuccess):
        result.save_pdf("./invoice.pdf")
    elif isinstance(result, InvoiceFailure):
        for error in result.errors:
            print(error.message)

Context Manager

python
# Sync
with ThelawinClient(api_key="...") as client:
    result = client.invoice().generate()

# Async
async with AsyncThelawinClient(api_key="...") as client:
    result = await client.invoice().generate()

Source Code

github.com/steviee/thelawin-clients/tree/main/python

ZUGFeRD 2.3 & Factur-X 1.0 compliant