Skip to main content

factora-python

PyPI version License: MIT

Official Python SDK for the Factora E-Invoicing API — create legally compliant German and European electronic invoices (XRechnung and ZUGFeRD, both based on EN 16931) from a single HTTP call.

Installation

pip install factora

Requires Python 3.9+.

Quickstart

An invoice is created with one POST to /api/v1/invoices/atomic/. The SDK wraps that endpoint in FactoraClient.create_atomic_invoice().

import uuid

from factora import FactoraAPIError, FactoraClient

client = FactoraClient(api_key="fa_live_your_api_key")

payload = {
    "api_mode": "atomic_single_post",
    "invoice_header": {
        "invoice_number": "RE-2026-0001",
        "invoice_date": "2026-08-06",
        "currency": "EUR",
        "invoice_type": "380",
        "buyer_reference": "04011000-12345-34",  # Leitweg-ID, required by BR-DE
        "profile": "xrechnung",  # or "en16931"; omit to get "xrechnung"
    },
    "seller_snapshot": {
        "name": "Muster GmbH",
        "street": "Musterstrasse 1",
        "zip": "10115",
        "city": "Berlin",
        "country": "DE",
        "vat_id": "DE123456789",
        "contact": {
            "name": "Alex Muster",
            "phone": "+49 30 1234567",
            "email": "billing@muster-gmbh.example",
        },
    },
    "buyer": {
        "name": "Beispiel AG",
        "street": "Beispielweg 7",
        "zip": "80331",
        "city": "Muenchen",
        "country": "DE",
        "vat_id": "DE987654321",  # or buyer["contact"]["email"]
    },
    "items": [
        {
            "description": "Consulting services, August 2026",
            "quantity": "2",
            "unit": "H87",  # UN/ECE Rec. 20 code, H87 = piece
            "unit_price_net": "750.00",
            "vat_rate": "19.00",
        }
    ],
    "validation_totals": {
        "net_amount": "1500.00",
        "vat_amount": "285.00",
        "gross_amount": "1785.00",
    },
}

try:
    result = client.create_atomic_invoice(
        payload,
        idempotency_key=str(uuid.uuid4()),
    )
except FactoraAPIError as exc:
    print(f"HTTP {exc.status_code}: {exc}")
    print(exc.response_data)  # full response envelope, incl. errors[]
else:
    print(result["valid"], result["data"])

FactoraClient is also a context manager, which closes the underlying HTTP session for you:

with FactoraClient(api_key="fa_live_your_api_key") as client:
    result = client.create_atomic_invoice(payload)

Idempotency

Pass idempotency_key with a value you generate (a UUID works well). Replaying the same key returns the original result instead of creating a second invoice — safe to use for retries after a timeout.

Request essentials

The API validates strictly; a rejected request comes back as HTTP 400 with a list of errors rather than a partially created invoice.

Top level

Field Required Notes
api_mode yes Must be "atomic_single_post"
invoice_header yes See below
validation_totals yes net_amount, vat_amount, gross_amount
seller_snapshot or mandant_id yes Exactly one — sending both or neither returns 400
buyer yes See below
items yes At least one line item

invoice_header — invoice_number and invoice_date are required; currency defaults to "EUR" and invoice_type to "380" (commercial invoice). profile also lives here: "xrechnung" (default) or "en16931". It is not a top-level field — sent at the top level it is ignored without an error and the invoice silently falls back to "xrechnung". The resolved profile is always returned in the response.

seller_snapshot — name is required.

buyer — name is required.

items[] — each line needs description, quantity, unit (UN/ECE Rec. 20 code, e.g. "H87"), unit_price_net and vat_rate.

Additional rules under invoice_header.profile: "xrechnung"

The German CIUS (BR-DE rules) requires these on top of the base fields:

  • invoice_header.buyer_reference — the Leitweg-ID
  • seller_snapshot.city and seller_snapshot.zip
  • seller_snapshot.contact.phone and seller_snapshot.contact.email
  • buyer.city and buyer.zip
  • an electronic address for the buyer — either buyer.vat_id with a DE prefix, or buyer.contact.email

Response envelope

Every call returns the same envelope:

{
  "valid": true,
  "data": { "...": "created invoice" },
  "errors": [],
  "meta": { "...": "request metadata" }
}

Error entries always carry code, severity and message, and may additionally include field, rule, bt (the EN 16931 business term) and location.

Error handling

Any non-2xx response, and any transport failure, raises FactoraAPIError:

Attribute Description
status_code HTTP status code, or None if the request never reached the server
response_data Decoded response envelope, or None when the body was absent or not JSON
try:
    client.create_atomic_invoice(payload)
except FactoraAPIError as exc:
    if exc.status_code == 400 and exc.response_data:
        for error in exc.response_data.get("errors", []):
            print(error["code"], error["severity"], error["message"])
    else:
        raise

Configuration

FactoraClient(
    api_key="fa_live_your_api_key",
    base_url="https://console.factora.software",  # default
    timeout=30,                                    # seconds, default
)

API keys are issued in the Factora Console. Keys prefixed fa_test_ target the sandbox, fa_live_ target production. Keep them out of source control — read them from an environment variable or a secrets manager.

Documentation

Full API reference: https://console.factora.software/docs

License

MIT — see LICENSE.

Metadata

Release files for factora 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for factora 0.1.2
File Size Uploaded
factora-0.1.2.tar.gz 8.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for factora 0.1.2
File Interpreter ABI Platform
factora-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 16.6 kB

Release files / factora-0.1.2.tar.gz

Download URL factora-0.1.2.tar.gz
Size 8.8 kB
Tags Source
SHA-256 checksum
How to use checksums
d326cdd58f58c73ab44b762ef17b4cef4bc9979ba8bb3cd61b0b7ab4f613e36f
BLAKE2b-256 checksum
How to use checksums
8cf65abb87c6d44201a7144b06096c9a797e8271eae0f6c5a4f715eac57b0d34
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 6, 2026.

Transparency log

Release files / factora-0.1.2-py3-none-any.whl

Download URL factora-0.1.2-py3-none-any.whl
Size 7.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2ae05d122b3cc48315a3a531f6883d66df625d2c6dcd3798a50255532e8ce291
BLAKE2b-256 checksum
How to use checksums
5e598d16e559a316beefb15c39848ad9dabe99fb28950a8c140d55ca18ff4e53
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page