SevDesk Archiver
Standalone Python tool that builds a self-contained local archive of your SevDesk documents (invoices, credit notes, vouchers). Each document is stored as a PDF plus a JSON sidecar with the full SevDesk metadata, and the archive ships its own standalone HTML viewer — no database, no server required.
- Idempotent — re-running only fetches what is missing or changed
- Self-serving — the archive directory contains a static
index.htmlviewer and a standaloneserve.py(Python stdlib only) - Type-aware — invoices, credit notes, and vouchers with correct status/type labels (German)
- Resilient — exponential backoff on rate limits and transient network errors
- Integrity-checked — SHA-256
pdf_hashper document;verifycross-checks manifest, files, sidecars, and hashes - No DB — plain files on disk, easy to back up, inspect, or diff
Run it
No install needed — uvx fetches and runs the latest release in an ephemeral environment:
uvx sevdesk-archiver@latest --help
Or install persistently:
uv tool install sevdesk-archiver
sevdesk-archiver --help
Configure
Two things are needed for the archive command: a SevDesk API token and a target directory. Any of the following works:
1. Command-line arguments — highest precedence:
uvx sevdesk-archiver@latest archive \
--api-token "$SEVDESK_API_TOKEN" \
--target /path/to/archive
2. Environment variables — export once, run anywhere:
export SEVDESK_API_TOKEN=your_sevdesk_token
export ARCHIVE_TARGET=$HOME/Documents/sevdesk-archive
uvx sevdesk-archiver@latest archive
3. .env file in the working directory — auto-loaded on startup:
# .env
SEVDESK_API_TOKEN=your_sevdesk_token
ARCHIVE_TARGET=.
cd /path/to/archive && uvx sevdesk-archiver@latest archive
Get your SevDesk API token from https://my.sevdesk.de/admin/userManagement (Benutzer → API-Token).
One-line in-place refresh
Drop a .env (with ARCHIVE_TARGET=. and your token) into an archive directory, then refresh it with a single line from inside that directory:
cd /path/to/archive && uvx sevdesk-archiver@latest archive
Running headless (cron / systemd timer)
The archive command is idempotent and exits non-zero on any error, so it is safe and monitorable as a scheduled job. Three things matter for unattended operation:
- Add a periodic full-history sweep. The default date range (1st of previous month … today) filters by document date, not booking date. A voucher entered today but dated three months ago — or an invoice finalized long after its invoice date — falls outside the rolling window and would never be archived. A regular sweep over your full history closes that gap; since runs are idempotent, it only costs metadata fetches.
- Prevent overlapping runs. Rate-limit backoff can stretch a run past the next scheduled start; use
flock(or a systemd timer, which never overlaps) so two runs don't write concurrently. - Pin the version.
@latestin a cron job means unattended auto-upgrades; pin and bump deliberately.
# hourly incremental refresh (default window: 1st of previous month … today)
15 * * * * cd /path/to/archive && flock -n /tmp/sevdesk-archiver.lock \
uvx sevdesk-archiver@0.1.1 archive
# weekly full sweep (catches backdated / late-booked documents) + integrity check
30 3 * * 0 cd /path/to/archive && flock /tmp/sevdesk-archiver.lock sh -c \
'uvx sevdesk-archiver@0.1.1 archive --after 2020-01-01 && uvx sevdesk-archiver@0.1.1 verify'
Cron mails you the output on non-zero exit (or point the job at a dead-man's-switch service like healthchecks.io).
Token hygiene: for headless use, keep SEVDESK_API_TOKEN outside the archive directory (crontab environment, or systemd EnvironmentFile=). A .env inside the archive is convenient interactively, but the archive folder is designed to be copied around (USB stick, S3, …) — and the token would travel with every copy.
Commands
# Build / refresh the archive (default range: 1st of previous month … today)
sevdesk-archiver archive
# Limit the date range
sevdesk-archiver archive --after 2026-01-01 --end 2026-03-31
# Include vouchers (incoming invoices)
sevdesk-archiver archive --vouchers
# See what would happen — no files written
sevdesk-archiver archive --dry-run
# Serve the archive over HTTP and open the browser (index.html needs http://)
sevdesk-archiver serve
# Deep integrity check: manifest ↔ files ↔ sidecars ↔ hashes
sevdesk-archiver verify
# Add SHA-256 pdf_hash to sidecars that lack it (existing archives)
sevdesk-archiver verify --backfill-hashes
--target <dir> overrides ARCHIVE_TARGET on any command.
Archive layout
$ARCHIVE_TARGET/
├── index.html # viewer (loads manifest.json via fetch)
├── manifest.json # summary of all entries
├── logo.png
├── serve.py # standalone HTTP server (stdlib only)
├── serve-archive.sh # wrapper: ./serve-archive.sh
└── files/
├── inv-20260115-RE-2026_0001-Mustermann_GmbH.pdf
├── inv-20260115-RE-2026_0001-Mustermann_GmbH.json
└── …
The files/ subdirectory is the authoritative store. manifest.json is regenerated on every run and is safe to delete — it'll be rebuilt from the sidecars. The index.html / serve.py helpers are copies of the shipped templates; you can re-run sevdesk-archiver archive at any time to refresh them.
Each sidecar carries the full SevDesk document, archive metadata, and a SHA-256 pdf_hash ("sha256:<hex>") so verify can catch silent corruption.
Once archived, the folder is self-contained. You can copy it anywhere (USB stick, S3, attached storage) and open it with:
cd /path/to/archive
./serve-archive.sh # or: python3 serve.py
No pip install, no sevdesk-archiver, no SevDesk API access required to browse — just Python 3's standard library.
Library use
from sevdesk_archiver import SevDeskClient, verify_archive
from sevdesk_archiver.archive import archive
client = SevDeskClient(api_token="...")
for event in archive(client, target_dir="/path/to/archive"):
print(event["message"])
report = verify_archive("/path/to/archive")
Development
uv sync
uv run pytest
uv run ruff check src tests
uv run mypy src
See CLAUDE.md for the release process and project conventions, and CHANGELOG.md for version history.
License
Apache-2.0 — see LICENSE.
Metadata
Release files for sevdesk-archiver 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sevdesk_archiver-0.2.0.tar.gz | 98.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sevdesk_archiver-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 198.4 kB
Release files / sevdesk_archiver-0.2.0.tar.gz
| Download URL | sevdesk_archiver-0.2.0.tar.gz |
|---|---|
| Size | 98.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cc0f49c79447db241d619c0ab013b8b0fe88f60a64b0089bfb47b3d4e5a369e6
|
|
BLAKE2b-256 checksum How to use checksums |
921140ca74654a9670d94f4991eedd391bcb182876d733c9bdf9705b8aebd450
|
| 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 Sep 24, 2026.
Transparency logRelease files / sevdesk_archiver-0.2.0-py3-none-any.whl
| Download URL | sevdesk_archiver-0.2.0-py3-none-any.whl |
|---|---|
| Size | 100.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8c8849d0eafd1121e8320196b4d1e6c57de3353a4e382d162f8e7f3e7f56cd4d
|
|
BLAKE2b-256 checksum How to use checksums |
6cbb33a4273f388d6aee13fb730552646c6f4c1f677e853664061801040d56b2
|
| 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 Sep 24, 2026.
Transparency log