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.1

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.1
File Size Uploaded
sevdesk_archiver-0.2.1.tar.gz 99.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sevdesk-archiver 0.2.1
File Interpreter ABI Platform
sevdesk_archiver-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 201.3 kB

Release files / sevdesk_archiver-0.2.1.tar.gz

Download URL sevdesk_archiver-0.2.1.tar.gz
Size 99.9 kB
Tags Source
SHA-256 checksum
How to use checksums
04d9fe0b97809e438f0870712bf4b2bbe7324a6a56bcd3d802d9c80c090e69df
BLAKE2b-256 checksum
How to use checksums
884dd23b0a62aff23758b3c7da715140c8d5d34378fa30c2856e53b4503fb793
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.1-py3-none-any.whl

Download URL sevdesk_archiver-0.2.1-py3-none-any.whl
Size 101.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d167d8fff8e78a0bfaa7ba69d6414ff500fed387d2d42b8de723f42157ae2b75
BLAKE2b-256 checksum
How to use checksums
58ad608fd693d45569c21bca5dca82af587fdeff3dd100b3a247830c99097bdc
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

This release

0.2.1 This release

2 release files

0.2.0

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