Skip to main content

SevDesk Archiver

PyPI version CI Python License

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.html viewer and a standalone serve.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_hash per document; verify cross-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:

  1. 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.
  2. 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.
  3. Pin the version. @latest in 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)

Source distribution for sevdesk-archiver 0.2.0
File Size Uploaded
sevdesk_archiver-0.2.0.tar.gz 98.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sevdesk-archiver 0.2.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

0.2.1

2 release files

This release

0.2.0 This release

2 release files

0.1.1

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