Skip to content

Privacy API

The Privacy API is what the Privacy pages use. Every endpoint is for signed-in people: an API key gets 401 sign in required. Each change is written to the audit log under your name. For what each feature does, read the guides under Data protection first.

Permission Allows
privacy.view Every GET below except the request export
dsr.handle Registering and working data subject requests, and reading the settings
privacy.manage Every change to settings, registers, retention, holds and breaches, and the dry run
reports.approve The MLRO’s review of a flagged request
entities.view_pii Needed with dsr.handle to download a request’s export
Status Meaning Examples
401 Not signed in, or called with an API key sign in required
403 Missing permission missing permission privacy.manage; not allowed; not allowed: exporting a person's data decrypts it, which needs the personal data permission (entities.view_pii)
404 No such request, customer, hold, breach, notification, task, activity or transfer in your workspace not found; not found: no such customer; not found: no such case
409 The action doesn’t fit the current state the MLRO must review this request first; run a dry run first: run a dry run (after the last policy change, within 30 days) and review it before switching the purge on; conflict: Customer C-1042 is already under a legal hold; conflict: this hold is already released; conflict: the request is completed; conflict: the clock is already stopped; conflict: the clock isn't stopped; conflict: this request isn't waiting for the MLRO
422 A field fails its rules shorter than the legal minimum: Transactions must be kept at least 1830 days (Ghana Anti-Money Laundering Act, 2020 (Act 1044) s.32(3): not less than five years); invalid: unknown category "x"; invalid: give a reason of 3 to 2000 characters; invalid: Ghana Data Protection Act, 2012 (Act 843) allows no extension (Act 843 s.35(10)); invalid: the deadline can move to 9 Jan 2027 at the latest; invalid: give the legal basis for refusing; invalid: Ghana Data Protection Act, 2012 (Act 843) doesn't let the clock stop (Act 843 s.35(10)); invalid: the discovery time can only move earlier (deadlines run from it)
428 / 202 A change that needs a second person’s approval. See Approvals

These endpoints can need a second person’s approval, under the workspace’s approval policy:

Endpoint Action type
PUT /api/v1/privacy/retention Retention and purging (privacy.retention)
PUT /api/v1/privacy/retention/purge Retention and purging
PUT /api/v1/privacy/settings, only when the jurisdictions change Retention and purging
POST /api/v1/privacy/holds Legal holds (privacy.legal_holds)
POST /api/v1/privacy/holds/{id}/release Legal holds

When approval is required, a call without an X-Change-Reason header answers 428 after checking the change, and a call with one answers 202 with the change request. See the Change requests API.

Needs privacy.view, privacy.manage or dsr.handle. Returns what the Privacy pages build their choices from:

Field Contents
laws Every law in the table: code, name, authority, dsr (deadline, rule, citation, per-kind overrides each with their own rule and citation, extension, and stop_clock with stop_clock_rule where the law lets the clock stop), breach (per recipient: hours, rule, citation, when required), erasure_exemption, aml (years and citation), tipping_off, rights
categories The retention categories: key, name, description, clock, actions, aml
request_kinds access, rectification, erasure, restriction, objection, portability
lawful_bases legal_obligation, contract, legitimate_interests, public_interest, consent, vital_interests
data_categories The categories lawful bases are recorded for, with key and name
Endpoint Does Permission Success
GET /api/v1/privacy/settings The data protection settings privacy.view, privacy.manage or dsr.handle 200
PUT /api/v1/privacy/settings Change them privacy.manage 204
GET /api/v1/privacy/activities The record of processing privacy.view 200
POST /api/v1/privacy/activities Add an activity privacy.manage 201 {"id": …}
PUT /api/v1/privacy/activities/{id}, DELETE … Change or remove one privacy.manage 204
GET /api/v1/privacy/lawful-bases The lawful basis per data category privacy.view 200
PUT /api/v1/privacy/lawful-bases/{category} Set one privacy.manage 204
GET /api/v1/privacy/transfers The transfer register, with the hosting region and country privacy.view 200
POST /api/v1/privacy/transfers Add a transfer privacy.manage 201 {"id": …}
PUT /api/v1/privacy/transfers/{id}, DELETE … Change or remove one privacy.manage 204
Field Rules Meaning
jurisdiction Two letters, a known law or any country code The main law. EU and GB are accepted
extra_jurisdictions Up to 10 Other laws that apply
hosting_region Up to 64 characters Where the data is hosted
hosting_country Two letters Transfers elsewhere are cross-border
controller_name Up to 200 The institution’s legal name; defaults to the workspace name
dpo_user_id, dpo_name, dpo_email The DPO
registration_ref, registration_expires Registration with the data protection authority

The response also has purge_enabled and laws (as in the reference data). The first read creates the settings (jurisdiction and hosting country from the workspace’s country) and pre-fills the registers.

Activity, lawful basis and transfer fields

Section titled “Activity, lawful basis and transfer fields”
  • Activity: name (2-200), purpose, lawful_basis, data_subjects, data_categories, recipients (lists of up to 50), transfers, retention, security_measures. Pre-filled activities have a key.
  • Lawful basis: basis, reference (up to 500), note (up to 2,000). {category} is one of the data category keys; an unknown one gives 404.
  • Transfer: recipient (2-200), recipient_role (processor, sub_processor, controller, regulator, group_company, other), destination_country, purpose, data_categories, safeguard (none_needed, adequacy, contract_clauses, binding_rules, consent, authority_approval, legal_obligation, other), reference, active. Responses add cross_border and needs_safeguard.
Endpoint Does Permission Success
GET /api/v1/privacy/retention Each category’s period, minimum and cut-off, the purge state, the last dry run and purge, and can_enable privacy.view 200
PUT /api/v1/privacy/retention Change periods and actions privacy.manage 204
POST /api/v1/privacy/retention/dry-run Count what a purge would remove today, and record it privacy.manage 200 with the run
PUT /api/v1/privacy/retention/purge {"enabled": true} or false privacy.manage 204
GET /api/v1/privacy/runs?mode=dry_run|purge&limit= Recent dry runs and purges (default 20, at most 100) privacy.view 200

PUT /api/v1/privacy/retention takes the categories to change; others keep theirs:

{
"policies": {
"transactions": { "retention_days": 2196, "action": "pseudonymise" },
"account_events": { "retention_days": 365 }
}
}

retention_days is 1 to 36,500 and never below the minimum (422). action is delete or pseudonymise where the category offers it; leave it out to keep the current one. Shortening a period, or changing to delete, switches the purge off.

A run has mode, status (running, completed, failed), requested_by_name, cutoffs (per category: retention_days, minimum_days, cutoff, action), counts (per category: eligible, held, deleted, pseudonymised, partitions, kept, note), error, started_at and finished_at.

Switching the purge on answers 409 unless a completed dry run is newer than the last policy or jurisdiction change and less than 30 days old.

Endpoint Does Permission Success
GET /api/v1/privacy/holds?status=active|released Holds privacy.view 200
POST /api/v1/privacy/holds Place one privacy.manage 201 {"id": …}
POST /api/v1/privacy/holds/{id}/release Release one: {"reason": "…"} (3-2,000 characters) privacy.manage 204
{
"scope": "customer",
"target_id": "0192f3a4-5b6c-7d8e-9f01-23456789abcd",
"reason": "Litigation: Accra High Court suit 2026/114",
"reference": "Court order of 2 October 2026"
}

scope is workspace (no target_id), case, customer or report. The response lists each hold with its target_label (case or report number, or customer reference), who set and released it, when, and why.

Endpoint Does Permission Success
GET /api/v1/privacy/requests?status= Requests (at most 500), open ones first by due date. status is active (not yet answered), a status, or empty for all dsr.handle or privacy.view 200
POST /api/v1/privacy/requests Register one dsr.handle 201 with the request
GET /api/v1/privacy/requests/{id} One request dsr.handle or privacy.view 200
PATCH /api/v1/privacy/requests/{id} Assign, verify identity, extend or withdraw dsr.handle 200 with the request
POST /api/v1/privacy/requests/{id}/mlro-review The MLRO’s review: {"note": "…"} (3-2,000) reports.approve 200
POST /api/v1/privacy/requests/{id}/clock/pause Stop the clock while waiting for identity or a clarification: {"reason": "…"} (3-1,000). Only where the request’s law allows it (UK), 422 otherwise dsr.handle 200 with the request
POST /api/v1/privacy/requests/{id}/clock/resume Restart the clock; the due date and any extension move later by the time it was stopped dsr.handle 200 with the request
POST /api/v1/privacy/requests/{id}/complete Close a non-erasure request with its outcome dsr.handle 200
POST /api/v1/privacy/requests/{id}/erase Decide an erasure request: {"response_note": "…"} (optional) dsr.handle 200
GET /api/v1/privacy/requests/{id}/export Download the zip for an access or portability request. It holds every row and is streamed, with a Content-Length dsr.handle and entities.view_pii 200 application/zip
Field Required Meaning
customer_id Yes The customer the request is about
kind Yes access, rectification, erasure, restriction, objection, portability
law No The law the deadline follows; default the workspace’s jurisdiction
channel No email, letter, branch, phone, portal, other (default)
received_at No When it reached the institution; default now. Not more than an hour in the future
details No What the person asked (up to 4,000 characters)
identity_verified, identity_notes No The identity check
assignee_id No Who handles it; they are notified

The response has the request’s number, due_at, due_rule (the rule as the law words it, with its citation), status (open, or mlro_review when flagged), tipping_off and overdue. A flagged request never says why.

A request also carries:

Field Meaning
can_pause_clock The request’s law lets the clock stop (today, the UK)
clock_paused_at, clock_pause_reason Set while the clock is stopped. A stopped request is never overdue
clock_paused_seconds How long the clock was stopped so far; already added to due_at and extended_due_at
erasure_held An erasure is due (the retention period has ended) but a legal hold, an open case, an open screening match or a report still requires the records. erasure_due_at stays the day the period ended. Only the MLRO (reports.approve) is told: for everyone else it is always false, and the request looks like an ordinary scheduled erasure, because “postponed” with no legal hold in sight would reveal a case or a report
hold_reasons Why the erasure is postponed, only on GET …/requests/{id} and only for the MLRO (reports.approve): legal holds on the workspace, the customer, a case or a report, open cases, and reports inside their retention period. Each has kind (workspace, customer, case, report, open_case, report_retention), label, reason and reference. Always empty for everyone else

The MLRO check is repeated. Every GET of the list or of a request, and every action below, checks open requests again and moves one to mlro_review (with tipping_off: true) when a case or a report now concerns the person. An action attempted at that moment answers 409 the MLRO must review this request first.

  • PATCH takes any of status (open, in_progress, withdrawn), assignee_id, unassign, identity_verified, identity_notes, extend_to with extension_reason (at least 3 characters). A flagged request can only be withdrawn until the MLRO has reviewed it.
  • complete takes decision (allowed per kind: access and portability exported or refused; rectification rectified or refused; restriction restricted or refused; objection objection_upheld, objection_rejected or refused), legal_basis (required to refuse or reject) and response_note.
  • erase decides from retention; you don’t choose the outcome. The response’s decision is erased, pseudonymised or exempt_scheduled, with legal_basis, erasure_due_at and erased_at, and, for the MLRO only, erasure_held when a hold postpones an erasure that is due. See Erasure and the AML exemption.
Endpoint Does Permission Success
GET /api/v1/privacy/breaches The register (at most 500), with each breach’s next_due_at and pending_notifications privacy.view 200
POST /api/v1/privacy/breaches Record a breach privacy.manage 201 with the breach
GET /api/v1/privacy/breaches/{id} One breach with its notifications and tasks privacy.view 200
PUT /api/v1/privacy/breaches/{id} Change it privacy.manage 200 with the breach
POST /api/v1/privacy/breaches/{id}/notifications/{nid} Record that a notification was sent: notified_at, reference, note privacy.manage 204
POST /api/v1/privacy/breaches/{id}/tasks Add a task: title (2-300), optional assignee_id, due_at privacy.manage 201 {"id": …}
PUT /api/v1/privacy/breaches/{id}/tasks/{tid} {"done": true} or false privacy.manage 204
GET /api/v1/privacy/breaches/{id}/export Download the report for the regulator (zip) privacy.manage 200 application/zip

A breach takes title (3-200), description, data_categories, affected_count, laws (default the workspace’s jurisdictions), risk (unlikely, risk, high_risk), occurred_at, discovered_at (required; not in the future; not before occurred_at), contained_at, status (open, contained, closed) and measures. Each notification has law, law_name, recipient (authority or subjects), authority, due_at (null when the law sets no fixed hours), rule, citation, required, notified_at, reference, note and overdue.