Skip to main content

Hosted single-tenant DICOM pseudonymization API wrapping dcm-anonymizer (PS3.15 Basic Profile)

Project description

dcm-anon-vault

A hosted, single-tenant DICOM pseudonymization API. Upload DICOM files over HTTP, get back a ZIP of pseudonymized outputs plus a tamper-evident audit log. Stripe billing is built in for pay-as-you-go tier enforcement.

Wording note — In DICOM and clinical-research practice the process is colloquially called "anonymization" (and the upstream engine ships as dcm-anonymizer). Under EU GDPR (Recital 26 + WP29 Opinion 05/2014 + EDPB Guidelines 01/2025) the OUTPUT of PS3.15 Basic Profile is pseudonymized personal data, NOT anonymized. We use "pseudonymization" throughout this README and in all customer-facing copy; "anonymize" appears only as the technical verb on DICOM tags.


1. What it is

dcm-anon-vault wraps the dcm-anonymizer engine (PS3.15 Basic Confidentiality Profile, PyPI: dcm-anonymizer) in a FastAPI service. You deploy one instance per customer (single-tenant), point it at a SQLite volume, and give each customer an API key. The service enforces per-tier file quotas, logs every pseudonymization event with a SHA-256 audit chain, and integrates with Stripe for upgrade billing.

All PHI scrubbing is done by dcm-anonymizer, which implements the DICOM PS3.15 Basic Application Level Confidentiality Profile. No data ever leaves the machine you deploy on.

UID re-mapping is deterministic per customer (we use SHA-256(api_key) as the engine salt), so re-running the same source study produces the same target SOPInstanceUID / PatientID — enabling longitudinal cohort linkage that random UIDs would destroy.


2. Why hosted vs running the CLI locally

Concern CLI (pip install dcm-anonymizer) Vault (hosted)
Audit log retention You manage the JSON file Persisted to SQLite, queryable
Multi-user access Manual key sharing Per-customer API keys + tiers
Billing Manual invoicing Stripe Checkout built in
Deployment Per-workstation install Deploy once on Fly.io or your VPS
CI / pipeline integration Possible but fragile POST /v1/anonymize from any client

If you process fewer than 50 DICOMs per month, the free tier is sufficient. If you need auditability across a team, or want to gate access by subscription, the hosted vault is the right tool.


3. Tiers (subject to change pre-1.0)

Tier Price Quota Isolation
Free €0/mo 50 files/month Shared single-tenant
Pro €99/mo Fair-use 10K files/mo Single-tenant (your own deploy)
Annual €999/yr Fair-use 10K files/mo Same as Pro; ~17 % off
Enterprise Contact SLA, BAA, async jobs, SSO Isolated VPS, dedicated support

Free-tier customers receive 429 Too Many Requests with a Retry-After header once they hit the monthly cap. Upgrading via Stripe Checkout flips the tier in the database on signed-webhook receipt.

A 14-day Pro trial is enabled by default (STRIPE_TRIAL_DAYS=14).


4. Deploy in 5 minutes on Fly.io

Prerequisites: flyctl installed and authenticated.

git clone https://github.com/Ces107/dcm-anon-vault
cd dcm-anon-vault

fly apps create dcm-anon-vault
fly volumes create vault_data --size 1 --region cdg

fly secrets set \
  DCM_API_KEYS="customer1:$(openssl rand -hex 32)" \
  STRIPE_API_KEY="sk_test_REPLACE_ME" \
  STRIPE_PRICE_ID="price_REPLACE_ME" \
  STRIPE_PRICE_ID_ANNUAL="price_REPLACE_ME" \
  STRIPE_WEBHOOK_SECRET="whsec_REAL_SECRET_HERE"

fly deploy
curl https://dcm-anon-vault.fly.dev/health

Required Stripe configuration before any paid customer:

  • Monthly price → STRIPE_PRICE_ID.
  • Optional annual price → STRIPE_PRICE_ID_ANNUAL.
  • Webhook endpoint at https://<your-app>/v1/billing/webhook pointing at the events: checkout.session.completed. Copy the signing secret into STRIPE_WEBHOOK_SECRETthe service refuses to process unsigned events.

5. API quick reference

# Pseudonymize one or more DICOMs (returns ZIP)
curl -X POST https://<host>/v1/anonymize \
  -H "X-API-Key: <your-key>" \
  -F "files=@scan.dcm" \
  --output result.zip

# Check usage / quota for the current UTC month
curl https://<host>/v1/usage -H "X-API-Key: <your-key>"

# Start a Stripe Checkout upgrade (monthly or annual)
curl -X POST https://<host>/v1/billing/checkout-session \
  -H "X-API-Key: <your-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "success_url":"https://example.com/success",
    "cancel_url":"https://example.com/cancel",
    "plan":"annual",
    "customer_email":"buyer@example.com"
  }'

Response headers from /v1/anonymize carry X-Files-Processed, X-Files-Failed, X-Files-Rejected-BurnedIn, and X-Audit-Sha256.


6. Local development

cp .env.example .env          # fill in real values
pip install -e ".[dev]"
uvicorn dcm_anon_vault.app:app --reload --port 8080

python -m pytest -q
python -m ruff check src tests
python -m mypy --strict src

7. Scope, disclaimers, regulatory posture

This is a research utility. It is NOT a medical device.

dcm-anon-vault is intended for the preparation of DICOM datasets for research, software development, and educational use. It is not intended to inform clinical diagnosis or therapeutic decisions and is not a medical device under Regulation (EU) 2017/745 (MDR) Art 2(1) nor under 21 CFR Part 820. If you intend to use it as a pre-processing step in a clinical pipeline, the obligation to perform conformity assessment falls on you as the deployer / modifier.

GDPR posture. PS3.15 Basic Profile is a pseudonymization operation, not anonymization, per EDPB Guidelines 01/2025 on Pseudonymisation and WP29 Opinion 05/2014. Output remains personal data and must be handled accordingly. The hosted plane receives and briefly processes raw PHI on the customer's behalf, which makes the operator a processor under GDPR Art 4(8). A Data Processing Agreement (DPA) is required before any EU customer can be onboarded; we publish a template DPA at /legal/dpa (work in progress).

HIPAA posture. Receiving raw DICOM from a US Covered Entity makes the operator a Business Associate by operation of law (45 CFR 160.103), regardless of contract. Until a BAA programme is in place, the hosted service is not available to US Covered Entities. Self-host the service inside your own HIPAA-compliant environment instead.

Storage at rest. The audit log is stored in SQLite without disk-level encryption. Customers requiring encryption-at-rest should deploy on an encrypted volume (LUKS, KMS-backed EBS, Fly encrypted volumes) and / or substitute Postgres with TDE via DCM_DB_URL.

What this software does NOT do. No burned-in pixel-data PHI removal; we reject files declaring BurnedInAnnotation==YES with HTTP 422 rather than silently leak PHI. No SR (Structured Report) text-item deep redaction (only the engine's PS3.15 actions). No IHE BIR / ATNA audit message emission. No KMS-backed encryption. No Conformance Statement (PS3.4 §2.2) — write to us if you need one for a hospital procurement evaluation.

This README is the canonical scope statement. Marketing copy MUST match it.

Contact: plusultra.dev@proton.me · Issues: https://github.com/Ces107/dcm-anon-vault/issues


Copyright © 2026 César Pereiro García — MIT License. See NOTICE.md for upstream attribution; SECURITY.md for vulnerability reporting; CHANGELOG.md for release history.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dcm_anon_vault-0.2.0.tar.gz (25.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dcm_anon_vault-0.2.0-py3-none-any.whl (21.1 kB view details)

Uploaded Python 3

File details

Details for the file dcm_anon_vault-0.2.0.tar.gz.

File metadata

  • Download URL: dcm_anon_vault-0.2.0.tar.gz
  • Upload date:
  • Size: 25.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for dcm_anon_vault-0.2.0.tar.gz
Algorithm Hash digest
SHA256 cd4c848a0f38be076c37d8d6675b3af7fc290451db2ca08886275ae21caa6c1e
MD5 8c75eeaf2eae898d184bfcf3b6e7660a
BLAKE2b-256 8eadc01f80ba8fa3243f029123b2fe1e611e6a23c94812e2f67a2ae3088e2dc8

See more details on using hashes here.

File details

Details for the file dcm_anon_vault-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: dcm_anon_vault-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 21.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for dcm_anon_vault-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2b2dc155408c82b6a5e6ea3b2661685016baae4177f15c2cbc20f2e2d80e2c5c
MD5 18d1f2efda0fa0a71688ea2efafc9a8d
BLAKE2b-256 23257021c3f0bdd0190c8d235bf13409359e773496b781cf8fb6733bc2495e44

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page