Automation · Legal and compliance
How to build data retention enforcement
The privacy notice says support tickets are kept for three years. The help desk holds every ticket since 2016, and so does the warehouse copy of it. The model behind a retention schedule that actually deletes, the prompts that build it, and what it takes to do it safely.
Built with Tray Headless
- System Retention schedule
- Step Find what is past its date
- Step Check for holds
- Step Delete and read back
- System Zendesk
Nothing is deleted until the legal hold check has passed, and every deletion is read back and recorded.
The short answer
What is data retention enforcement?
Data retention enforcement has four parts: the retention schedule written as a rule per system and record type, a regular search for records past their date, a check against legal holds and open obligations before anything is deleted, and a record of what was deleted, when and under which rule. The usual failure is the copies. The source system gets cleaned and the warehouse, the export in a shared drive and the marketing tool keep every record, so the schedule is only true in the place nobody else reads.
Stage 6 of 7: Retention and deletion. Part of Compliance automation, end to end : every stage, the systems it runs on and the guide that builds it.
What matters here
- Write the schedule as rules per system. A policy document nobody can run deletes nothing.
- Include the copies. The warehouse and the exports hold the same records as the source, for longer.
- Check for legal holds before every run. A deleted record under a hold is far worse than a record kept too long.
- Have the owner approve the first runs. Once the counts look right, let it run on its own.
- Record every deletion by rule and count. Proving you deleted is half the control.
Who this is for
You run privacy, legal or data governance. The retention schedule is written down, nothing enforces it, and the oldest records in most systems are older than the policy allows.
How it works in practice
What happens each run, from the schedule to records actually gone.
- 1
The schedule is written as rules
For each system and record type: how long it is kept, from which date, and what happens at the end, delete or make anonymous.
- 2
Records past their date are found
In each system on the schedule, including the warehouse and other copies, counted by rule.
- 3
Holds and obligations are checked
Legal holds, open disputes, live contracts and financial records with their own retention period are taken out of the run.
- 4
The owner approves while the rule is new
For the first runs of each rule, the system owner sees the count and a sample, and approves before anything is deleted.
- 5
Records are deleted and read back
In each system, in batches, with a check afterwards that they are gone and a retry for anything that failed.
- 6
The run is recorded
Rule, system, count found, count held back with the reason, count deleted and the date.
What retention enforcement is made of
Four parts. The third is the one that makes deleting safe.
A schedule you can run
One rule per system and record type, with the period, the start date it counts from, and the action at the end.
Every copy in scope
The source system, the warehouse, the marketing and analytics tools, and the shared drives where exports end up.
Holds checked first
Legal holds, disputes, live contracts and records with their own required period, checked before every run and never skipped.
A record of what went
Counts by rule, what was held back and why, and the read-back result, kept longer than the records themselves.
The Tray Headless prompts
Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.
Once per project, run
/tray-workflows:set-workspace
to pick the workspace these build in. Point it at a sandbox first.
- 1
Set up, then write the schedule as rules
The schedule is the control. The rest is mechanism.
Headless skills
build-workflowUse build-workflow. The systems in play are Salesforce, Zendesk, Marketo, Snowflake, Google Drive, Box and Slack, or whatever we run in those seats. Before you plan anything, tell me which of them are already authenticated in the workspace, because I do not want a connector stubbed that I have not authenticated. Then turn our retention schedule into a table: system, record type, how long it is kept, the date it counts from (created, closed, last activity, contract end), the action at the end (delete or make anonymous), and an owner. Add a row for every copy of each record type: the warehouse tables, the marketing database, exports in shared drives. Flag any record type that exists in more than one place with no rule for the copy.
- 2
Find what is past its date
Count first, delete later.
Headless skills
build-workflowtray-gotchasUse build-workflow and tray-gotchas. Each month, for every rule, find the records past their date in that system. Count them and take a sample of ten. Do not delete anything in this step. Write the counts and samples to Snowflake, so the first run is a report of how far behind the schedule each system is. Handle systems that can only be searched in pages, and dates that are blank: a record with no close date is never past its date, so report it instead of deleting it.
- 3
Check holds before every run
A deleted record under a legal hold is the worst outcome on this page.
Before any record is deleted, remove from the run anything that is: Under a legal hold, from the hold register legal keeps Tied to an open dispute, claim or investigation Tied to a contract still in force A financial or tax record with its own required period If the hold register cannot be read, stop the whole run and tell legal. Never treat a missing hold list as an empty one. Record every record held back, with the reason.
- 4
Delete with approval while a rule is new
Deleting is permanent, so earn the right to run it unattended.
Headless skills
build-workflowtray-patternsUse build-workflow and tray-patterns. For the first three runs of each rule, send the system owner a Slack message with the count, the sample and the holds taken out, and buttons to approve or stop. Delete only after approval. After three approved runs with no problems, let the rule run on its own and send the owner the counts afterwards. Delete in batches. After each batch, read back a sample to confirm the records are gone, and retry anything that failed. Where the rule says make anonymous, replace the personal fields and keep the record. Delete the copies in the same run as the source, so the warehouse never holds what the source no longer does.
- 5
Record what went
Proving you deleted is half the control.
For every run, write to Snowflake: rule, system, records found, held back with reasons, deleted, made anonymous, failed, and the date. Keep this record longer than any record it describes. Report monthly: systems behind their schedule, rules with no owner, record types with copies not covered by a rule, and runs that stopped because the hold register could not be read.
- 6
Check it end to end, then hand the schedule to privacy
Because the schedule changes and the people who own it should change it.
Run the per-step checks and the whole-workflow audit before this touches production. Test with a record under a legal hold, a record with no close date, and a record that exists in both the source and the warehouse, and confirm each is handled correctly. Then open the same workflow in Tray Build so privacy and legal can change the rules, the owners and the approval step in the visual canvas.
What it connects to
Records live in the business apps, copies live everywhere else, and the hold register decides what stays.
Salesforce
Find closed accounts, old leads and contacts past their date, and delete or make them anonymous.
Reads and writes
Zendesk
Find closed tickets past their period and delete them with their attachments.
Reads and writes
Marketo
Remove people whose records were deleted at the source, so the marketing copy does not outlive it.
Reads and writes
Snowflake
Delete the warehouse copies in the same run, and keep the record of every run.
Reads and writes
Google Drive
Find exports and spreadsheets past their period in the folders the schedule covers.
Reads and writes
Same build, other stacks
The design does not change if you run something else in one of these seats. The same prompts build it against Microsoft Dynamics 365, Google BigQuery, Microsoft Teams, Jira, SharePoint or HubSpot.
Connections in this build
Field mapping, templates and common problems for each pairing: Salesforce + Zendesk, Marketo + Salesforce, Snowflake + Marketo and Google Drive + Salesforce.
Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.
Running it in production
This deletes records permanently, across systems. The checks before and after matter more than the deletion itself.
It runs on the platform, not on your laptop
Searches, holds checks, batches and read-backs run on the same engine, with a full history of each run.
No hold list, no run
If the legal hold register cannot be read, the run stops. A missing list is never treated as an empty one.
Credentials are managed, never written into the build
Delete permission across the CRM, help desk and warehouse is about as sensitive as it gets. Each is a separate authentication in your workspace, scoped and separately revocable.
Privacy owns the schedule
Rules, owners and the approval step open in Tray Build, changed by the team accountable for the policy.
It earns the right to run alone
Each rule runs with the owner's approval until three runs have gone cleanly, then runs on its own with the counts reported.
Questions people ask
Why include the warehouse and exports?
Because they hold copies of the same records, usually for longer. Cleaning the source and leaving the copies means the schedule is only true in one place.
What if a record is under a legal hold?
It stays, whatever the schedule says, and the run records that it was held back and why. If the hold register cannot be read, nothing is deleted.
Should deletion run without anyone approving it?
Not at first. The owner approves the first few runs of each rule after seeing the count and a sample. Once those have gone cleanly, the rule runs on its own and the owner gets the counts.
How is this different from a deletion request?
A deletion request is one person asking for their data to go. Retention enforcement applies the schedule to everyone's records on a regular cycle. Both use the same hold checks.
Does this make us compliant?
No workflow does that. It makes the schedule you wrote actually run, and keeps the record. Whether the schedule itself is right is a question for your legal team.
Related guides
Legal and compliance
How to build data subject request automation
Search every system instead of the ones you remember, verify identity before disclosing, track the statutory clock, and record what was found. The prompts.
Legal and compliance
How to build a consent and preference sync
Give consent one owner, propagate a withdrawal in seconds, keep the evidence, and never let a sync re-subscribe anybody. The Headless prompts that build it.
Data operations
How to build a CRM to warehouse sync
Capture history instead of current state, handle deletes and field changes, land raw then model, and prove the row counts. The Headless prompts that build it.
Last reviewed October 2026.