factora-python
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",
"profile": "xrechnung", # or "en16931"
"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
},
"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" |
profile |
no | "xrechnung" (default) or "en16931" |
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).
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 profile: "xrechnung"
The German CIUS (BR-DE rules) requires these on top of the base fields:
invoice_header.buyer_reference— the Leitweg-IDseller_snapshot.cityandseller_snapshot.zipseller_snapshot.contact.phoneandseller_snapshot.contact.emailbuyer.cityandbuyer.zip- an electronic address for the buyer — either
buyer.vat_idwith aDEprefix, orbuyer.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.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file factora-0.1.0.tar.gz.
File metadata
- Download URL: factora-0.1.0.tar.gz
- Upload date:
- Size: 8.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
823ad1b452229efb47618dadf11cc4775f5f812691b6be2560b230e8aed2df9c
|
|
| MD5 |
b59971b67a383061e1aa24580349d344
|
|
| BLAKE2b-256 |
864921647d8f96e2128fc3cf7a119df4ed89e5b817ff85a1d8f81825a3a1c330
|
File details
Details for the file factora-0.1.0-py3-none-any.whl.
File metadata
- Download URL: factora-0.1.0-py3-none-any.whl
- Upload date:
- Size: 7.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7dc014fbedf258a69c667aa3133a814b6f115e7e77c974150413cb39d6cc2cd1
|
|
| MD5 |
1d7a7d80b6fea7a02d78f117f2034b9d
|
|
| BLAKE2b-256 |
be3570eb016699bffacd8e33e4e919a27d27d7f8cf669e0e47b50637a1aba3dd
|