Retention & Deletion
Retention is the mechanism that lets you keep records exactly as long as your obligations require: no shorter, and no longer. This guide explains how retention policies are defined, how they attach to documents, how expired records move through review-gated disposition to destruction, and how deletion behaves when legal holds apply. Workspace admins manage policies and approve dispositions; viewers have read-only access.
A retention policy is a named, workspace-scoped rule that answers two questions: how long is a record kept, and what happens when that time is up. Each policy has a unique name, an optional description, either a fixed duration in days or an event trigger the clock starts from, a grace period in extra days after expiry before the record enters disposition, and a disposition action that decides what happens at expiry: review_then_destroy or retain_indefinitely.
A duration-based policy counts a fixed number of days from ingest. An event-based policy starts the clock from a trigger event: ingest_date (when the document entered Talonic) or document_date (a date carried by the document itself, for example an invoice date). Talonic's compliance triage can propose event dates it finds in document content. Proposed dates are suggestions only: a document whose trigger date is not confirmed never gets an expiry date computed from a guess, so an unconfirmed proposal never triggers disposition.
# Create a 10-year policy with a 30-day grace period (admin only)
curl -X POST "$API_URL/records/retention-policies" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Invoices 10y",
"description": "Tax-relevant invoices, 10 years from document date",
"duration_days": 3650,
"event_trigger": "document_date",
"grace_period_days": 30,
"disposition_action": "review_then_destroy"
}'
# Assign it to every document classified as an invoice
curl -X POST "$API_URL/records/retention-assignments" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"policy_id": "<policy-id>",
"scope_type": "document_type",
"scope_id": "invoice"
}'Assignments and resolution: most specific wins
A policy takes effect when it is assigned to a scope. Three scopes exist: source connection (every document ingested through that connection), document type (every document classified as that type), and document (one specific document). When more than one assignment could apply, the most specific one wins: document beats document type, and document type beats source connection. Example: your Gmail connection carries a 6-year policy and the document type "invoice" carries a 10-year policy. An invoice from that Gmail connection gets 10 years. One specific invoice with a direct "retain indefinitely" assignment is retained indefinitely.
Retention state per document
| Parameter | Type | Description |
|---|---|---|
| active | state | Within its retention period. Normal access; no disposition pending. |
| pending_disposition | state | Past expiry plus grace period. Waiting in the disposition review queue. The document remains fully accessible. |
| disposed | state | Destruction approved and executed. Content is gone; the tombstone row and full audit history remain. |
The retention engine runs on a daily schedule. It resolves the effective policy for each document, computes and stores retain_until, and moves documents past retain_until plus the grace period into pending_disposition when their policy says review_then_destroy. Each engine run is summarized in the audit trail (retention.set and disposition.pending events), and each document's resolved policy, expiry date, and state are visible on the document itself and in document list filters.
How disposition works
Disposition is the controlled end of a record's life. Talonic never silently destroys an expired record. The path is: the document passes retain_until plus grace and enters the review queue. Nothing is destroyed at this point. An admin reviews the queue and approves destruction with a typed confirmation ("confirm": "DESTROY"), which is recorded with the approver's identity. Immediately before destruction, the system re-checks for active legal holds; if any hold covers the document, destruction fails closed and the document stays in the queue. Destruction then removes the stored content and extracted occurrences, keeps the document row as a tombstone, and issues a disposition certificate.
# List documents pending disposition
curl "$API_URL/records/dispositions?state=pending_disposition" \
-H "Authorization: Bearer $TOKEN"
# Approve destruction of one document (admin only, typed confirmation)
curl -X POST "$API_URL/records/dispositions/$DOCUMENT_ID/approve" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"confirm": "DESTROY"}'{
"disposed": true,
"certificate_id": "c2f0a7e4-6d1b-4c58-9a3e-8b7f6d5c4e3a"
}Every executed disposition produces a certificate recording the document (by tombstone reference), the filename, the SHA-256 hash of the destroyed content, the retention policy that applied, who approved the destruction and when, when destruction was executed, and confirmation that the legal hold check passed. Certificates are listed at GET /records/disposition-certificates and outlive the records they describe. The destruction itself is also written to the hash-chained audit trail as a document.disposed event, so the fact and circumstances of destruction enjoy the same tamper evidence as every other event.
Soft delete vs. destruction
Two different things
| Parameter | Type | Description |
|---|---|---|
| Soft delete | archive mode | Triggered by ordinary delete actions when archive mode is on. The document is marked deleted and hidden from listings, but content remains in storage and nothing about its history is lost. Audit event: document.deleted. |
| Destruction | disposition only | Triggered only by an approved disposition. Content is permanently deleted; the row remains as a tombstone with the content hash and audit linkage. Audit event: document.disposed, plus a certificate. |
Every deletion path checks for active legal holds before proceeding and refuses if one applies: user-initiated document deletion, disposition-driven destruction, administrative cleanup, and full workspace deletion. Fail-closed means the check must positively succeed for deletion to proceed. A hold always beats a retention expiry: a document that is both expired and held stays exactly where it is until the hold is released. After destruction, the tombstone preserves the document's identity, its content hash, and its complete audit history, so you can always answer what the record was, when it existed, who touched it, and who approved its destruction.
retain_until and lifecycle tiering to archival storage classes (both are designed as infrastructure templates and are not deployed; today retention is enforced at the application layer). Fully automatic event-based retention from extracted dates is intentionally not offered: extracted dates remain proposals requiring human confirmation.