Python client for the docs101 invoicing API
Project description
docs101
Python client for the docs101 invoicing API — create customers, generate EU-compliant invoices, and export to DATEV.
Installation
pip install docs101
Quick Start
from docs101 import Docs101Client
client = Docs101Client(api_key="ak_live_YOUR_KEY_HERE")
# Create a customer
customer = client.customers.create(
organization_name="Acme Corp",
email="billing@acme.com",
contact_type="B2B",
vat_id="DE123456789",
language="English",
)
customer_id = customer["id"]
# Add an address
client.customers.create_address(
customer_id,
address_line_1="Musterstraße 1",
postal_code="10115",
city="Berlin",
country_code="DE",
is_default=True,
)
# Create an invoice
invoice = client.invoices.create(
customer_id=customer_id,
benefit_period_start="2026-04-01",
benefit_period_end="2026-04-30",
invoice_format="ZUGFERD",
)
invoice_id = invoice["invoice_id"]
# Add a position
client.invoices.add_position(
invoice_id,
title="Pro Plan — Monthly Subscription",
quantity=1.0,
unit_id="HUR",
unit_net_amount=25.00,
single_net_amount=25.00,
tax_rate=0.19,
tax_treatment_id="standard",
)
# Validate and finalize
validation = client.invoices.validate(invoice_id)
assert validation["valid"], f"Validation failed: {validation['errors']}"
client.invoices.finalize(invoice_id)
# Get PDF
pdf = client.invoices.get_pdf_url(invoice_id)
print(f"PDF ready: {pdf['filename']} — {pdf['url']}")
Features
- Typed exceptions —
AuthenticationError,ValidationError,NotFoundError,LimitExceededError, and more - Async job polling —
finalize()andcreate_datev()automatically poll until the job completes - DATEV export — Configure DATEV settings and trigger exports with automatic download handling
- ZUGFeRD, Peppol, FatturaPA, Facturae — Full support for EU e-invoicing formats
- Type hints — Full type annotations with
py.typedmarker (PEP 561)
Usage
Customers
# List all customers
customers = client.customers.list()
# Get a single customer
customer = client.customers.get(42)
# Update a customer
client.customers.update(42, email="new@acme.com")
# Manage addresses
addresses = client.customers.list_addresses(42)
client.customers.create_address(42, address_line_1="New St 1", city="Munich", country_code="DE")
client.customers.update_address(42, 1, city="Hamburg")
client.customers.delete_address(42, 1)
Invoices
# List invoices (paginated)
invoices = client.invoices.list(page=1, limit=25)
# Create, add positions, validate, finalize
invoice = client.invoices.create(customer_id=42, invoice_format="ZUGFERD")
invoice_id = invoice["invoice_id"]
client.invoices.add_position(invoice_id,
title="Consulting", quantity=10, unit_id="HUR",
unit_net_amount=150.00, single_net_amount=150.00,
tax_rate=0.19, tax_treatment_id="standard",
)
client.invoices.validate(invoice_id)
client.invoices.finalize(invoice_id)
# Download links
pdf = client.invoices.get_pdf_url(invoice_id)
xml = client.invoices.get_xml_url(invoice_id)
# Status management
client.invoices.mark_as_sent(invoice_id)
client.invoices.mark_as_paid(invoice_id,
paid_date="2026-04-15",
payment_method="BANK_TRANSFER",
)
# Duplicate or cancel
new = client.invoices.duplicate(invoice_id)
client.invoices.cancel(invoice_id)
DATEV Export
# Configure DATEV
client.exports.configure_datev(
consultant_number=1234567,
client_number=12345,
chart_of_accounts="SKR03",
)
# Run export (polls automatically)
result = client.exports.create_datev(
start_date="2026-01-01",
end_date="2026-03-31",
)
# Download all parts
for download_id in result["download_ids"]:
url_info = client.downloads.get_url(download_id)
print(f"Download: {url_info['url']}")
Templates
templates = client.templates.list()
template = client.templates.get(1)
Error Handling
from docs101 import (
Docs101Error,
AuthenticationError,
ValidationError,
NotFoundError,
LimitExceededError,
VatOverrideRequiredError,
JobFailedError,
Docs101TimeoutError,
)
try:
client.invoices.finalize(invoice_id)
except LimitExceededError as e:
print(f"Limit reached: {e.used}/{e.limit}, resets {e.reset_date}")
except VatOverrideRequiredError:
client.invoices.finalize(invoice_id, vat_override_confirmed=True)
except JobFailedError as e:
print(f"Job failed: {e.error_message}")
except Docs101TimeoutError:
print("Job timed out — check status manually")
Examples
See the examples/ directory for complete, runnable scripts:
create_invoice.py— Full workflow: customer → invoice → PDFbulk_invoicing.py— Bulk invoicing from CSVdatev_export.py— DATEV export + download
API Documentation
Contributing
- Clone the repo
- Create a virtual environment:
python -m venv .venv && source .venv/bin/activate - Install dev dependencies:
pip install -e ".[dev]" - Run tests:
pytest tests/ -v
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
docs101-0.1.0.tar.gz
(13.8 kB
view details)
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
docs101-0.1.0-py3-none-any.whl
(13.0 kB
view details)
File details
Details for the file docs101-0.1.0.tar.gz.
File metadata
- Download URL: docs101-0.1.0.tar.gz
- Upload date:
- Size: 13.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7da2e50b18f2e3a03e52083a90fed08d8b3f83b7fd5b0f9964218d05139428b3
|
|
| MD5 |
03462a283c5898df9b8dd0506eb20afa
|
|
| BLAKE2b-256 |
a91630350eceb5be16c69ea204c2e20528e944febf632c4b20b3f8ae2ae908d2
|
File details
Details for the file docs101-0.1.0-py3-none-any.whl.
File metadata
- Download URL: docs101-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05f81fd4604e8d78014b6dab98d9ab9d9e2087313d8105a68287ec823693a319
|
|
| MD5 |
bd697adf1fc81c4113a5999ee7ee5daa
|
|
| BLAKE2b-256 |
aec507047fe8ce23dcaae38facca611a2d9367b417c043fe1dbe0819771fbd02
|