API reference · Hubtask API 0.1.0
privacy
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
Responses
200One page of the cases403An error per RFC 9457 Problem
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
Request body application/json — DataSubjectRequestCreate
Responses
201The case DataSubjectRequest4XXAn error per RFC 9457 Problem
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
Request body application/merge-patch+json — DataSubjectRequestUpdate
Responses
200The case DataSubjectRequest4XXAn error per RFC 9457 Problem
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
Headers
Request body application/json — DataSubjectRequestExtension
Responses
200The case, with the extended deadline and the original beside it DataSubjectRequest4XXAn error per RFC 9457 Problem
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
Query parameters
Responses
200What each hold would keep ErasurePreview4XXAn error per RFC 9457 Problem
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
Request body application/json — ProcessingRestriction
Responses
200The state that was set ProcessingState4XXAn error per RFC 9457 Problem
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
Responses
200The register4XXAn error per RFC 9457 Problem
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
Responses
200The consent record after the withdrawal ConsentRecord4XXAn error per RFC 9457 Problem
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
Responses
200The consent record ConsentRecord4XXAn error per RFC 9457 Problem
Codes this operation names
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
200The caller's view OwnAiPosition4XXAn error per RFC 9457 Problem
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
200The caller's view afterwards OwnAiPosition4XXAn error per RFC 9457 Problem
curl -X POST "$HUBTASK_URL/privacy/ai-objection:noticed" \ -H "Authorization: Bearer $HUBTASK_TOKEN"