Skip to content

GET /privacy/requests

The data subject requests this workspace is handling

Soonest deadline first, the open ones by default. A right somebody exercised is a case with a statutory deadline, and this is the list whoever answers for it reads - which is why the overdue ones can be asked for on their own.

Query parameters

NameTypeRequiredDescription
statusDataSubjectRequestStatus
  • RECEIVED
  • IN_PROGRESS
  • COMPLETED
  • REJECTED
optional
kindDataSubjectRequestKind
  • ACCESS
  • ERASURE
  • PORTABILITY
  • RESTRICTION
  • OBJECTION
  • RECTIFICATION
optional
due_within_daysinteger optionalOnly the requests whose deadline falls inside that many days, overdue ones included.
include_closedboolean
  • default: false
optional
cursorstring optional
sizeinteger
  • default: 50
  • maximum: 200
optional

Responses

  • 200 One page of the cases
  • 403 An error per RFC 9457 Problem
Example bash
curl -X GET "$HUBTASK_URL/privacy/requests" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /privacy/requests

Record a right somebody has exercised

Opens the case with its statutory deadline - thirty days from receipt unless the caller names a different one, because the period is a legal matter and an installation may have to answer sooner. Nothing is collected, exported or erased by this call: what happens next is the controller's decision, taken by moving the case to IN_PROGRESS.

RECTIFICATION is accepted as a tracked case although a correction is an ordinary write: a deadline somebody is answerable for is worth recording whether or not the work needs a special path.

Headers

NameTypeRequiredDescription
Idempotency-Keystring (uuid) optionalA UUID; identical requests return the same result for 24 h.

Request body application/json — DataSubjectRequestCreate

NameTypeRequiredDescription
kindDataSubjectRequestKind
  • ACCESS
  • ERASURE
  • PORTABILITY
  • RESTRICTION
  • OBJECTION
  • RECTIFICATION
requiredThe right that was exercised.
scopeDataSubjectRequestScope
  • TENANT
  • INSTALLATION
optionalHow far the case reaches.
subject_account_idstring (uuid) optional
subject_emailstring (email) optional
due_atstring (date-time) optionalThe deadline, when it is not thirty days from receipt.
notesstring optional
target_idstring (uuid) optionalThe backup target an access or portability export is written to.

Responses

Example bash
curl -X POST "$HUBTASK_URL/privacy/requests" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Idempotency-Key: $(uuidgen)" \  -H "Content-Type: application/json" \  -d '{  "kind": "ACCESS",  "scope": "TENANT",  "subject_account_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c",  "subject_email": "anna@example.org",  "due_at": "2026-09-16T10:00:00Z",  "notes": "string",  "target_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c"}'

PATCH /privacy/requests/{requestId}

Move a case along

The state machine is RECEIVED → IN_PROGRESS → COMPLETED | REJECTED, and an illegitimate transition is refused by name rather than ignored. Moving an ACCESS, PORTABILITY or ERASURE case to IN_PROGRESS is what starts the work: the archive or the erasure runs as a job, and the case is completed by that job rather than by a second call.

An erasure needs its mode before it can start - ANONYMIZE keeps the authorship as a former user and the workspace's content with it, FULL_DELETE takes the person's own contributions too. The choice rests with the controller, because tenant data touches third parties' rights.

Path parameters

NameTypeRequiredDescription
requestIdstring (uuid) required

Request body application/merge-patch+json — DataSubjectRequestUpdate

NameTypeRequiredDescription
statusDataSubjectRequestStatus
  • RECEIVED
  • IN_PROGRESS
  • COMPLETED
  • REJECTED
optional
erasure_modeErasureMode
  • ANONYMIZE
  • FULL_DELETE
optionalANONYMIZE keeps the authorship as a former user and the workspace's content with it; FULL_DELETE takes the person's own contributions too.
handled_bystring (uuid) optional
rejection_reasonstring optionalRequired when the case is rejected.
notesstring optional
target_idstring (uuid) optional

Responses

Example bash
curl -X PATCH "$HUBTASK_URL/privacy/requests/{requestId}" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Content-Type: application/merge-patch+json" \  -d '{  "status": "RECEIVED",  "erasure_mode": "ANONYMIZE",  "handled_by": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c",  "rejection_reason": "string",  "notes": "string",  "target_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c"}'

POST /privacy/requests/{requestId}:extend

Extend a case's deadline once

Art. 12(3) GDPR allows the period to be extended once, by at most two further months, where the request is complex or the requests are many. An open case before its original deadline can be extended once, to a day at most three months after the day it was received, naming the reason and the day the person was informed. Hubtask records that the controller told the person; it does not write to them.

Both days are calendar days in the workspace's time zone: the new deadline is the end of due_on there, and informed_on lies between the day of receipt and today. A case answers extendable_until, the latest day it can be extended to, exactly while an extension can succeed - sending that day back as due_on is accepted.

A second extension, one at or after the original deadline, or one of a closed case is refused by name. A case of INSTALLATION scope needs the admin:tenants scope, and every workspace the person is a member of records the extension in its own audit trail. Idempotent under its Idempotency-Key.

Path parameters

NameTypeRequiredDescription
requestIdstring (uuid) required

Headers

NameTypeRequiredDescription
Idempotency-Keystring (uuid) optionalA UUID; identical requests return the same result for 24 h.

Request body application/json — DataSubjectRequestExtension

NameTypeRequiredDescription
due_onstring (date) requiredThe new deadline as a day; the case is due by the end of it in the workspace's time zone.
reasonDataSubjectRequestExtensionReason
  • COMPLEXITY
  • NUMBER_OF_REQUESTS
requiredWhy the deadline is extended: the request's complexity, or the number of requests the controller is handling.
informed_onstring (date) requiredThe day the controller informed the person of the extension and its reason: not before the day the request was received, not after today.

Responses

Example bash
curl -X POST "$HUBTASK_URL/privacy/requests/{requestId}:extend" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Idempotency-Key: $(uuidgen)" \  -H "Content-Type: application/json" \  -d '{  "due_on": "2026-09-16",  "reason": "COMPLEXITY",  "informed_on": "2026-09-16"}'

GET /privacy/requests/{requestId}/erasure-preview

What legal holds would keep from an erasure

A legal hold wins over an erasure as far as it reaches: what a hold covers is kept, the rest is erased, and the case closes as partly completed. This answers, before the erasure is started, what each hold in force would keep of this case's person - so the confirmation can say so. A hold on the person or on the whole workspace keeps the account itself; under any other hold it is anonymised as usual.

mode is the mode the preview is for, the case's own when left out, and ANONYMIZE when the case names none. Refused for a case that is not an erasure and for a closed one. A case of INSTALLATION scope needs the admin:tenants scope. The hold's reason is not part of the answer; the holds list carries it for those who may read it.

Path parameters

NameTypeRequiredDescription
requestIdstring (uuid) required

Query parameters

NameTypeRequiredDescription
modeErasureMode
  • ANONYMIZE
  • FULL_DELETE
optional

Responses

Example bash
curl -X GET "$HUBTASK_URL/privacy/requests/{requestId}/erasure-preview" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /accounts/{accountId}:restrict

Restrict the processing of an account's data (Art. 18)

A technical state rather than a lock: the account stays readable and its content stays where it is, and what stops is processing - automation rules and AI leave the record alone. Lifting it is the same call with restricted: false - refused while a legal hold keeps the account from an erasure, until the hold is lifted and the rest of the erasure has run.

Path parameters

NameTypeRequiredDescription
accountIdstring (uuid) requiredAn account identifier, always a UUID.

Request body application/json — ProcessingRestriction

NameTypeRequiredDescription
restrictedboolean required
reasonstring optionalWhy, for the audit trail.

Responses

Example bash
curl -X POST "$HUBTASK_URL/accounts/{accountId}:restrict" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Content-Type: application/json" \  -d '{  "restricted": true,  "reason": "string"}'

GET /privacy/consents

The consent register - who withdrew a purpose

For one purpose, every person whose newest record is a withdrawal, with since when and whether they or an administrator recorded it. For ai_processing this is who keeps their own content out of AI - and this register is the one place that list appears. For the people who manage members (MANAGE_MEMBERS).

Unpaged: it is bounded by the people of the workspace, ordered by name.

Query parameters

NameTypeRequiredDescription
purposeConsentPurpose required

Responses

  • 200 The register
  • 4XX An error per RFC 9457 Problem
Example bash
curl -X GET "$HUBTASK_URL/privacy/consents" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /privacy/consents:withdraw

Withdraw consent for an optional processing purpose (Art. 21)

Objection, as the one thing it can technically be: the optional processing stops and the core features keep working. A withdrawal is recorded rather than deleted - the record that somebody consented, and when they took it back, is what an operator needs in order to show which processing was lawful when.

Request body application/json — ConsentWithdrawal

NameTypeRequiredDescription
purposeConsentPurpose requiredThe optional processing a consent covers.
account_idstring (uuid) optionalWhose consent.
reasonstring optional

Responses

Example bash
curl -X POST "$HUBTASK_URL/privacy/consents:withdraw" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Content-Type: application/json" \  -d '{  "purpose": "ai_processing",  "account_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c",  "reason": "string"}'

POST /privacy/consents:give

Agree to an optional processing purpose

The caller's own agreement - for ai_processing, letting the content they authored back into AI after they kept it out. Only ever the caller's own: a consent for anybody else is refused with 403, privacy.consent_own_only, because nobody agrees in another's place. The withdrawal before it stays on record for the period it covered.

Request body application/json — ConsentGrant

NameTypeRequiredDescription
purposeConsentPurpose requiredThe optional processing a consent covers.
account_idstring (uuid) optionalWhose consent - only ever the caller's own.

Responses

Codes this operation names

Example bash
curl -X POST "$HUBTASK_URL/privacy/consents:give" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Content-Type: application/json" \  -d '{  "purpose": "ai_processing",  "account_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c"}'

GET /privacy/ai-objection

The caller's own view of keeping their content out of AI

Whether there is anything to choose here (shown: AI answers this workspace and more than one person works in it), the workspace's position - with the legal basis and whom to ask where AI is part of everybody's work - the caller's own choice, whether it takes effect, and whether they still have to be told that it stopped taking effect.

The caller keeps their content out with POST /privacy/consents:withdraw and lets it back in with POST /privacy/consents:give, both with the purpose ai_processing.

Responses

Example bash
curl -X GET "$HUBTASK_URL/privacy/ai-objection" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /privacy/ai-objection:noticed

Acknowledge that keeping one's content out stopped taking effect

Records that the caller read the notice: the workspace made AI part of everybody's work, so their choice to keep their content out no longer takes effect. Acknowledging twice is acknowledging once.

Responses

Example bash
curl -X POST "$HUBTASK_URL/privacy/ai-objection:noticed" \  -H "Authorization: Bearer $HUBTASK_TOKEN"