Data Lifecycle

Holofin tracks every document deletion with idempotent jobs and cryptographically signed receipts. This page covers the audit trail, the receipt format, and how to verify a receipt.

Overview

When a document reaches the end of its retention period or is purged as part of an account closure, Holofin creates a Deletion Job that tracks the deletion across every storage layer. Once all layers are confirmed deleted, the job is marked CONFIRMED and a signed Deletion Receipt is generated as cryptographic proof.

This gives your organization an auditable record of what was deleted, when, and why, for GDPR compliance reviews, internal audits, and regulatory inquiries.

Deletion Jobs

A Deletion Job is created whenever a document is scheduled for deletion. Each job is idempotent: retries, crashes and duplicate triggers reuse the same job instead of creating a new one.

Deletion Layers

Each job tracks deletion across three independent storage layers:

LayerDescription
primary_dbThe document record and all related database entries (extraction results, comments, classifications) have been deleted from the primary PostgreSQL database.
blob_deletedThe original uploaded file (PDF/image) has been removed from primary object storage.
artefact_deletedProcessing artefacts (thumbnails, intermediate files) have been cleaned up.

A job is only marked CONFIRMED once all three layers are true.

Triggers

  • retention_policy
    Document exceeded its configured retention period (ZDR, 30, 60, or 90 days) and was automatically scheduled for deletion.
  • account_purge
    All documents in an organization were scheduled for deletion as part of an account closure or data purge request.
  • manual
    Document was explicitly deleted by a user or API call.

Idempotency

Each Deletion Job is identified by a deterministic idempotency key, a SHA-256 hash of:

sha256("{tenant_id}:{resource_id}:{policy}:{scheduled_date}")

This means the same document + policy + date always produces the same job. If the system crashes and retries, or if a duplicate trigger fires, the existing job is reused instead of creating a new one. The attempt_count field tracks how many times a job has been started.

Deletion Receipts

When a Deletion Job reaches CONFIRMED, Holofin generates a Deletion Receipt: a JSON document, signed with HMAC-SHA256, that proves the deletion completed across all storage layers.

Receipt Payload

Deletion Receipt

{
  "receipt_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "schema_version": "1.0",
  "issued_at": "2026-03-01T14:30:00.000000+00:00",
  "issuer": "holofin.ai",
  "tenant": {
    "id": "d9ea4198-5477-4d4b-b285-5f3e47b5fa6c"
  },
  "job": {
    "idempotency_key": "a3f8c9e2b1d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4",
    "resource_type": "document",
    "resource_ref_hash": "b7d2e1f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8",
    "original_file_hash": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "page_count": 3,
    "policy": "30",
    "trigger": "retention_policy"
  },
  "deletion_confirmed": {
    "primary_db": true,
    "blob_deleted": true,
    "artefact_deleted": true,
    "confirmed_at": "2026-03-01T14:30:00.000000+00:00"
  }
}

Receipt Fields

FieldDescription
receipt_idUnique UUID for this receipt.
schema_versionReceipt schema version. Currently 1.0.
issued_atISO 8601 timestamp when the receipt was generated.
issuerAlways holofin.ai.
tenant.idUUID of the organization that owned the deleted document.
job.idempotency_key64-character hex SHA-256 hash that uniquely identifies this deletion job.
job.resource_typeType of resource deleted. Currently always document.
job.resource_ref_hashSHA-256 hash of the original resource ID. For privacy, the receipt stores only this hash, not the original ID. The hash can be used to verify a specific document was deleted without revealing the ID.
job.original_file_hashSHA-1 hash of the original uploaded file. Can be used to verify which exact file was deleted. null if the hash was not available at scheduling time.
job.page_countNumber of pages in the original document. null if not available.
job.policyRetention policy that was in effect when the deletion was scheduled (e.g. 30, 60, 90).
job.triggerWhat initiated the deletion: retention_policy, account_purge, or manual.
deletion_confirmed.primary_dbDatabase records deleted.
deletion_confirmed.blob_deletedOriginal file removed from object storage.
deletion_confirmed.artefact_deletedProcessing artefacts cleaned up.
deletion_confirmed.confirmed_atISO 8601 timestamp when deletion was confirmed across all layers.

Signature Verification

Each receipt includes a 64-character hex HMAC-SHA256 signature computed over the canonical JSON payload. This allows you to independently verify that a receipt has not been tampered with.

How Signing Works

  1. The receipt payload is serialized to canonical JSON: keys sorted alphabetically, compact separators (, and :), no whitespace.
  2. An HMAC-SHA256 is computed using a dedicated signing secret (DELETION_RECEIPT_SIGNING_SECRET).
  3. The resulting 64-character hex digest is stored alongside the receipt.

Verification Example (Python)

verify_receipt.py

import hmac
import hashlib
import json

def verify_receipt(payload: dict, signature: str, secret: str) -> bool:
    """Verify a Holofin deletion receipt signature."""
    canonical = json.dumps(payload, sort_keys=True, separators=(",", ":"))
    expected = hmac.new(
        secret.encode("utf-8"),
        canonical.encode("utf-8"),
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Use hmac.compare_digest (not ==) for timing-safe comparison.

Accessing Deletion Logs

Deletion jobs and receipts are available through the Holofin dashboard. All data is scoped to the authenticated user's organization; you cannot access receipts belonging to another tenant.

Individual receipts can be downloaded as JSON from the deletion history table. The Export All Receipts button downloads a ZIP archive containing one JSON file per receipt, named <receipt_id>.json. Each file includes both the payload and signature fields for independent verification.