Data and privacy
Where a workspace's data lives, how long it is kept, how a person gets a copy or has it erased, and why closing an account is not the same as erasure.

What it is
Four questions with real answers: what we hold about one person, how to hand it over, how to destroy it, and how long anything is kept if nobody asks. Plus one distinction that catches everybody — closing an account and erasing a person are two separate systems, and doing the first does not do the second.
How to get there
Admin → Privacy, with three tabs — Requests, Retention and Legal holds — and a Residency tab. Reading the queue and the retention settings needs privacy.request.view; running an export, approving an erasure and issuing a download link need privacy.request.manage; changing how long a category is kept needs privacy.retention.manage; placing or releasing a hold needs privacy.hold.manage.
A member asks for their own data from their own settings, without any of those keys.
How to use it
Answer a subject access request
- Admin → Privacy → Requests, create or open the request.
- Building the package walks the schema rather than a hand-written list of tables — 188 of 340 models are reachable from a person and are examined every time. Rows are capped at 10,000 per model, and truncation is stated in the package rather than applied silently.
- The package leads with an
index.html. A request answered with 188 JSON files is compliant and useless; the right being served is the right to understand what is held. - Credentials are redacted, not omitted — the column is shown with
[redacted]in it. A password hash is technically the subject's data and putting it in a downloadable zip is a hazard with no upside. - Hand over the signed link. It expires in seven days, and rotating its nonce invalidates every link already handed out — which is the only thing "revoke" can mean for a URL somebody may have forwarded.
Erase a person
Five protections, in order, because this is the one irreversible act in the product.
privacy.request.manageto approve — and it is **never reachable from an API token**.- You see the plan first: what is destroyed, what is kept, model by model.
- You type
ERASEto confirm. - A seven-day cooling-off window. Approval sets a date; the job runs later, and it can be cancelled with a reason until then.
- Holds are re-checked at execution, not only at approval. The window exists so time can pass, and a hold placed during it has to win.
What actually happens:
| Disposition | What happens | Examples |
|---|---|---|
| Erased | the row is deleted outright | sign-in tokens, sessions, device keys, key envelopes, push devices, calendar connections |
| Anonymised (the default) | the row is kept, the identity on it is scrubbed | sign-in history, the audit log, everything authored |
| Retained | untouched | invoices, credit notes, signatures, legal consents, the request itself |
The person's row is tombstoned, never deleted. Forty-five relations cascade from it, and deleting would take thousands of hours of logged time with it — hours already billed on issued invoices. The email becomes an address at a reserved domain that can never resolve, and sessions are revoked in the same write.
The audit log is anonymised rather than deleted, deliberately: deleting it would let a departing administrator erase the trail of what they did on the way out by filing an erasure request.
Close your own account
- Settings, and ask to close the account.
- This is a request, not a button that erases anything. It is recorded with a timestamp, every administrator of the workspace is notified in-app and on their phone — they are the only people who can remove a membership — and it is emailed to us so a workspace whose last administrator has gone quiet still ends in a deletion rather than in silence.
- Marking it completed flips a status. It does not run the erasure pipeline; that is a separate request raised from the Privacy screen.
The reason is that a workspace product cannot survive a button that erases a shared workspace from underneath a team. The tasks somebody was assigned, the comments they left and the documents they wrote belong to the organisation.
Set retention
- Admin → Privacy → Retention, eight categories.
- No policy means keep forever, which is what the product has always done and the only safe default for a workspace that never opens this screen.
| Category | Minimum |
|---|---|
| Activity | 30 days |
| Audit log | 365 days |
| Recycle bin | 7 days |
| Messages | 30 days |
| Attachments | 30 days |
| Notifications | 7 days |
| Webhook history | 7 days |
| Financial | 7 years |
The floors are in code, not in a row, and are enforced twice: the screen refuses to save a policy beneath one, and the nightly sweep clamps to it anyway — a setting written before a floor was raised must not be honoured now.
Place a legal hold
- Admin → Privacy → Legal holds, name the subject and the reason.
- A hold beats an erasure request, and it beats an export too. A hold that permits the custodian to download a complete copy of the held material is not a hold.
- The request is suspended, not refused. It keeps its statutory clock, carries a reason the subject can be shown, and resumes when the hold lifts. The reason names the fact of a hold and never the matter behind it.
- A workspace-wide hold stops the nightly deletion sweep outright. A hold naming one person narrows it instead — everybody else's rows are still deleted under policy.
- Releasing keeps the row. "Was this person under hold when they asked" is a question asked long after the matter closes.
What it affects
- Deletion is batched, at 5,000 rows per model per run. A workspace enabling a 30-day activity policy for the first time has millions of rows over the line; the backlog drains over several nights and the run history shows it draining.
- Every pass writes a row, including the ones that delete nothing. A dated series with no gaps is what distinguishes "nothing to do" from "the job stopped".
- Streaming the audit log holds retention back. If you stream to a SIEM, the audit cut-off is held at the oldest active sink's position, so the sweep cannot delete rows the SIEM has never seen.
- Residency is pinned per workspace, written automatically from the workspace's country and confirmable by an administrator. **A pin cannot be moved** — changing it would assert that data sitting in one jurisdiction sits in another.
- Only one region is currently pinnable. The screen says so plainly: a German workspace is told its country belongs in Frankfurt, that Frankfurt is not yet available, and that its data is therefore held where the workspace was created. A green tick over a region we cannot serve would be a false statement to a customer about where their data physically is.
- The subprocessor list is published at
/legal/subprocessors.
On mobile
The Privacy screen and the legal holds list are both in the phone app under Admin, as is residency. Building and handing over an export package is web-only — it produces a file that has to go somewhere.
Limits and gotchas
- End-to-end encrypted messages cannot be in an export. Direct messages arrive as ciphertext because that is all we have. Discussion posts are encrypted per row, so a channel switched on mid-life keeps its earlier history in the export in plain text — which is why the summary counts rows rather than models.
- Erasure is not one transaction. The walk touches up to 188 models; a single transaction across all of them would hold a connection open until it timed out and rolled back having done nothing, repeatedly. Each write stands alone and the whole run is safe to repeat, so a run that dies halfway is recovered by running it again.
- Evidence is kept without the personal data. The record that somebody was erased holds a hash of the address, not the address. Keeping an erased person's email forever in order to prove we erased them is the mistake that design avoids.
- A hold's coverage is exactly the export's coverage. A model the schema walk cannot attribute to a person is not protected, because by that same definition it holds nothing of theirs. Those models are named on both screens rather than left implicit.
- An expired download link is a 410, a bad one is a 404. The difference matters: 410 tells the subject the link lapsed rather than that we lost their data.
Related
- Privacy — the screen, tab by tab.
- Audit log — what is recorded, and streaming it out.
- Exports and downloads — the ordinary, non-DSAR way out.
- Messaging and encryption — why some messages cannot be exported.