Skip to content

GET /legal-holds

The legal holds in force

A hold overrides every retention rule and every deletion a person asks for, so who placed one and why is part of what it is. Released holds are shown too when asked for: a hold that has been lifted is what an auditor reads to see that it was.

Query parameters

NameTypeRequiredDescription
include_releasedboolean
  • default: false
optional

Responses

  • 200 The holds
  • 403 An error per RFC 9457 Problem
Example bash
curl -X GET "$HUBTASK_URL/legal-holds" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /legal-holds

Place a legal hold

Stops anything under it being deleted: a retention rule, a person emptying their own trash, a hard delete somebody asked for. It outranks the workspace's own configured periods, which is why placing one is not an ordinary member's power. Auditable.

Request body application/json — LegalHoldCreate

NameTypeRequiredDescription
scopeobject requiredWhat the hold covers.
kindstring
  • TENANT
  • CONTAINER
  • ITEM
  • ACCOUNT
required
idstring (uuid), or null optional
reasonstring
  • minLength: 1
  • maxLength: 2000
required

Responses

Example bash
curl -X POST "$HUBTASK_URL/legal-holds" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Content-Type: application/json" \  -d '{  "scope": {    "kind": "TENANT"  },  "reason": "string"}'

POST /legal-holds/{holdId}:release

Lift a legal hold

Records who lifted it, when, and why. Lifting is the moment the data under it becomes deletable again, so the reason is required rather than optional - "released" with no reason is the entry an auditor cannot act on. Auditable.

Path parameters

NameTypeRequiredDescription
holdIdstring (uuid) required

Request body application/json — LegalHoldRelease

NameTypeRequiredDescription
reasonstring
  • minLength: 1
  • maxLength: 2000
requiredWhy the hold is being lifted.

Responses

Example bash
curl -X POST "$HUBTASK_URL/legal-holds/{holdId}:release" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Content-Type: application/json" \  -d '{  "reason": "string"}'

GET /retention-policies

List the retention rules

Query parameters

NameTypeRequiredDescription
container_idstring (uuid) optional
effectiveboolean
  • default: false
optionalOnly the rules actually in force, including inheritance

Responses

  • 200 The rules
Example bash
curl -X GET "$HUBTASK_URL/retention-policies" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /retention-policies

Create a retention rule

New rules start in notify-only mode if their first run would affect more than 5% of the holdings. Extending beyond the data kind's upper bound requires a justification. Auditable.

Request body application/json — RetentionPolicy

NameTypeRequiredDescription
idstring (uuid) optional
scopeobject required
kindstring
  • TENANT
  • HUB
  • COLLECTION
optional
idstring (uuid), or null optional
data_kindstring requiredOne of the kinds /meta/capabilities lists under retention_data_kinds.
conditionstring, or null optionalAn optional CEL expression
retain_daysinteger
  • minimum: 0
required
actionstring
  • ARCHIVE
  • TRASH
  • ANONYMIZE
  • HARD_DELETE
  • EXPORT_THEN_DELETE
  • NOTIFY_ONLY
required
then_after_daysinteger, or null optional
then_actionstring, or null
  • ARCHIVE
  • TRASH
  • ANONYMIZE
  • HARD_DELETE
  • EXPORT_THEN_DELETE
  • null
optional
grace_daysinteger
  • default: 14
optional
notifyobject optional
before_daysinteger
  • default: 7
optional
recipientsarray of string optional
justificationstring, or null optionalMandatory when the upper bound is exceeded
enabledboolean
  • default: true
optional
export_target_idstring (uuid), or null optional
in_forceboolean optionalWhether this is the rule that would act in the container the listing was asked about (container_id).

Responses

Example bash
curl -X POST "$HUBTASK_URL/retention-policies" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Content-Type: application/json" \  -d '{  "id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c",  "scope": {},  "data_kind": "COMPLETED_ITEM",  "condition": "string",  "retain_days": 0,  "action": "ARCHIVE",  "then_after_days": 1,  "then_action": "ARCHIVE",  "grace_days": 14,  "notify": {},  "justification": "string",  "enabled": true,  "export_target_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c",  "in_force": true}'

PATCH /retention-policies/{policyId}

Correct a retention rule, or take it out of enforcement

Merge-patch: an absent key changes nothing. A rule that deletes data has to be correctable, and mode is what takes one out of enforcement without losing what it says - NOTIFY_ONLY reports what it would remove and removes nothing, which is where a new rule starts when its first run would affect more than 5% of the holdings, and where a rule somebody has doubts about belongs. Extending a period beyond the data kind's upper bound needs a justification, here as much as at creation, and the one stored is replaced rather than kept: the justification belongs to the period it justifies. The kind and the scope do not move. A rule that changed either would be a different rule under an old identifier, and the unique index over the pair is what makes "the rule for this kind at this level" a thing one can name at all. Auditable.

Path parameters

NameTypeRequiredDescription
policyIdstring (uuid) required

Headers

NameTypeRequiredDescription
If-Matchstring optionalThe ETag of the state last read (optimistic locking).

Request body application/merge-patch+json — RetentionPolicyUpdate

NameTypeRequiredDescription
conditionstring, or null optionalAn optional CEL expression.
retain_daysinteger
  • minimum: 0
optional
actionstring
  • ARCHIVE
  • TRASH
  • ANONYMIZE
  • HARD_DELETE
  • EXPORT_THEN_DELETE
  • NOTIFY_ONLY
optional
then_after_daysinteger, or null optional
then_actionstring, or null
  • ARCHIVE
  • TRASH
  • ANONYMIZE
  • HARD_DELETE
  • EXPORT_THEN_DELETE
  • null
optional
grace_daysinteger optional
notifyobject optional
before_daysinteger optional
recipientsarray of string optional
justificationstring, or null optionalWhy the period exceeds the kind's upper bound.
enabledboolean optional
export_target_idstring (uuid), or null optional

Responses

Example bash
curl -X PATCH "$HUBTASK_URL/retention-policies/{policyId}" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H 'If-Match: "<the ETag you read>"' \  -H "Content-Type: application/merge-patch+json" \  -d '{  "condition": "string",  "retain_days": 0,  "action": "ARCHIVE",  "then_after_days": 1,  "then_action": "ARCHIVE",  "grace_days": 1,  "notify": {},  "justification": "string",  "enabled": true,  "export_target_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c"}'

DELETE /retention-policies/{policyId}

Withdraw a retention rule

The rule stops applying. What it already did stands - retention deletes, and a deletion is not undone by withdrawing the instruction that caused it - and what it had marked for a future pass is unmarked, because an entry counting down towards a rule nobody holds any more would be deleted by a rule that does not exist. Withdrawing one that is not there is not an error. Auditable.

Path parameters

NameTypeRequiredDescription
policyIdstring (uuid) required

Responses

  • 204 Withdrawn
  • 4XX An error per RFC 9457 Problem
Example bash
curl -X DELETE "$HUBTASK_URL/retention-policies/{policyId}" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /retention-policies/{policyId}:preview

Determine the effect of a rule without executing it

Path parameters

NameTypeRequiredDescription
policyIdstring (uuid) required

Responses

  • 200 The preview
Example bash
curl -X POST "$HUBTASK_URL/retention-policies/{policyId}:preview" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /items/{itemId}:retain

Take an object out of the running retention period

Path parameters

NameTypeRequiredDescription
itemIdstring (uuid) required

Responses

Example bash
curl -X POST "$HUBTASK_URL/items/{itemId}:retain" \  -H "Authorization: Bearer $HUBTASK_TOKEN"