Skip to content

Not legal advice

dpdpkit is software that helps you implement obligations under India's Digital Personal Data Protection Act, 2023 and the DPDP Rules, 2025. It does not provide legal advice and does not guarantee compliance.

Retention and erasure

retention

Erasure schedules, pre-erasure warnings, legal holds and processor fan-out (DPDP Rules, Rule 8).

Fail-safe rules enforced here:

  • An erasure runs only after its warning is recorded as delivered, and only once the full warning period (retention.erasure_pre_notice_hours) has passed since delivery.
  • A failed or impossible warning, or a failing erasure handler, moves the schedule to needs_attention. Nothing is retried destructively without a person resolving it.
  • Activity by the principal after the warning cancels an inactivity-based erasure.
  • A legal hold blocks warning and erasure until it is released.
  • Ledger and audit rows are never erased; they are kept at least min_log_retention_days.

ErasureHandler module-attribute

ErasureHandler = Callable[[str, list[str]], None]

handler(principal, purposes) deletes or anonymises the principal's data. Raise to signal failure.

RetentionService

RetentionService(kit: Kit)

register_handler

register_handler(handler: ErasureHandler) -> ErasureHandler

Register a function that erases a principal's data for the given purposes.

record_activity

record_activity(principal: str, at: datetime | None = None) -> list[ErasureSchedule]

The principal logged in or contacted the fiduciary. Restarts inactivity clocks and cancels any inactivity erasure that has already been warned about (Rule 8(2)).

on_withdrawal

on_withdrawal(principal: str, purpose_id: str) -> ErasureSchedule | None

purpose_completed

purpose_completed(principal: str, purpose_id: str, *, actor: str = 'system') -> ErasureSchedule | None

schedule

schedule(principal: str, purpose_id: str, erase_at: datetime, *, reason: str, actor: str) -> ErasureSchedule

place_hold

place_hold(principal: str, reason: str, *, actor: str, purpose: str | None = None) -> LegalHold

release_hold

release_hold(hold_id: str, *, actor: str) -> LegalHold

holds

holds(principal: str | None = None) -> list[LegalHold]

run

run(now: datetime | None = None) -> ErasureRun

Send due warnings and perform due erasures. Safe to call as often as you like.

confirm_warning_delivery

confirm_warning_delivery(receipt_id: str, delivered: bool, *, at: datetime | None = None, error: str | None = None) -> ErasureSchedule

Called when a queued transport reports the final outcome of a warning.

erase_now

erase_now(principal: str, *, reason: str, actor: str, purposes: Iterable[str] | None = None) -> ErasureResult

Erase immediately because the principal asked (rights request). No warning is needed, but legal holds and purposes retained under a legal obligation are respected.

preview

preview(now: datetime | None = None, horizon: timedelta = timedelta(days=7)) -> list[PreviewItem]

schedules

schedules(principal: str | None = None, *, active_only: bool = True) -> list[ErasureSchedule]

needs_attention

needs_attention() -> list[ErasureSchedule]

resolve

resolve(schedule_id: str, action: Literal['retry', 'cancel'], *, actor: str, reason: str = '') -> ErasureSchedule

A person decides what happens to a needs_attention schedule.

log_floor

log_floor(occurred_at: datetime) -> datetime

Earliest time a ledger, audit or processing-log row written at occurred_at may be purged.

log_purgeable

log_purgeable(occurred_at: datetime, now: datetime | None = None) -> bool

ErasureResult dataclass

ErasureResult(erased_purposes: list[str] = list(), held_purposes: list[str] = list(), retained_purposes: list[str] = list(), failed: list[str] = list())

erased_purposes class-attribute instance-attribute

erased_purposes: list[str] = field(default_factory=list)

held_purposes class-attribute instance-attribute

held_purposes: list[str] = field(default_factory=list)

retained_purposes class-attribute instance-attribute

retained_purposes: list[str] = field(default_factory=list)

failed class-attribute instance-attribute

failed: list[str] = field(default_factory=list)