> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Breach incident register (GDPR Art. 33/34)

> Open, track, and close personal-data-breach incidents with a 72-hour notification attestation for your supervisory authority — the register GDPR Art. 33 expects you to keep.

# Breach incident register (GDPR Art. 33/34)

When personal data is breached, GDPR Art. 33(1) gives you at most **72 hours**
from the moment you become aware of the breach to notify your supervisory
authority. Where the breach is likely to result in a high risk to the people
affected, Art. 34 also obliges you to notify those data subjects without
undue delay. The breach incident register records that lifecycle — detection,
assessment, containment, notification, closure — and produces an attestation
proving whether the 72-hour window was met.

<Warning>
  This page describes Devotel Orbit's platform controls. It is **not legal
  advice.** Whether a given event is a notifiable breach, which authority to
  notify, and what your notification must contain are judgement calls for
  your data protection officer (DPO) and counsel.
</Warning>

All endpoints below are rooted at
`https://api.orbit.devotel.io/api/v1/compliance/breach-incidents`.

***

## The register records — you notify

The register records the breach lifecycle. It does **not** send the
notifications: your DPO contacts the supervisory authority and the affected
data subjects through your normal legal channels, then records in the
register when each notification went out. The register's attestation is the
evidence that those notifications happened inside the window — it never
touches a carrier, an email channel, or any outbound messaging itself.

Reads are available to any authenticated member of your workspace. Writes —
opening, updating, and recording notifications — are restricted to **owner**
and **admin** roles, because the register is a regulatory control. Every
write lands in your audit log with the actor and the incident reference.

***

## Lifecycle

An incident moves through:

`detected` → `under_assessment` → `contained` → `notified` → `closed`

Two terminal states end the lifecycle:

* `closed` — the incident was notified and is fully resolved.
* `no_notification_required` — the assessment concluded neither an Art. 33
  nor an Art. 34 notification is owed (for example, the data was encrypted
  and the key is uncompromised). Set `notification_required: false` and
  record the rationale in `remediation` before taking this branch.

An incident that still owes a supervisory-authority notification cannot be
closed: the API rejects the close with `409 Conflict` until you record the
Art. 33 notification or flip `notification_required` to `false`.

***

## Open an incident

`POST /compliance/breach-incidents` — requires an owner or admin API key.
The incident lands in status `detected` with a human reference like
`BR-2026-0001`, and `discovered_at` (default: now) starts the 72-hour clock.

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/breach-incidents \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Support mailbox accessed from an unauthorised account",
    "description": "An employee credential was used from an unmanaged device; mailbox contained customer email threads.",
    "severity": "high",
    "occurred_at": "2026-08-26T14:10:00.000Z",
    "affected_data_subjects": 412,
    "affected_records": 1830,
    "data_categories": ["email address", "message content", "contact details"],
    "notification_required": true
  }'
```

| Field                    | Type      | Notes                                                                                          |
| ------------------------ | --------- | ---------------------------------------------------------------------------------------------- |
| `title`                  | string    | **Required.** 2–200 chars.                                                                     |
| `description`            | string    | **Required.** 2–8000 chars.                                                                    |
| `severity`               | enum      | **Required.** `low`, `medium`, `high`, or `critical`.                                          |
| `discovered_at`          | datetime  | When you became aware. Defaults to now; this instant anchors the 72-hour deadline.             |
| `occurred_at`            | datetime  | When the breach is believed to have occurred, if known.                                        |
| `affected_data_subjects` | integer   | Estimated headcount of affected people.                                                        |
| `affected_records`       | integer   | Estimated number of records.                                                                   |
| `data_categories`        | string\[] | What personal data is involved.                                                                |
| `notification_required`  | boolean   | Defaults to `true` (authority notification owed). Flip to `false` with a documented rationale. |
| `remediation`            | string    | Containment notes; update as the response progresses.                                          |

Returns `201 Created` with the incident. Get one back with
`GET /compliance/breach-incidents/{id}`.

***

## Advance the lifecycle

`PATCH /compliance/breach-incidents/{id}` updates mutable fields and/or
moves the status forward:

```bash theme={null}
curl -X PATCH https://api.orbit.devotel.io/api/v1/compliance/breach-incidents/breachIncident_9qk2… \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "status": "under_assessment" }'
```

Every mutable field from the create body plus `status` can be patched, for
example recategorising severity once the scope is known, or updating the
affected counts as the assessment firms up.

***

## Record a notification

`POST /compliance/breach-incidents/{id}/notifications` — stamps the moment
a notification went out. This timestamp is what the 72-hour attestation
compares against the deadline.

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/breach-incidents/breachIncident_9qk2…/notifications \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "party": "supervisory_authority",
    "notified_at": "2026-08-27T10:20:00.000Z",
    "method": "authority_portal",
    "reference": "CASE-2026-11882",
    "notes": "Initial Art. 33 notification submitted through the DPA web portal."
  }'
```

| Field         | Type     | Notes                                                                         |
| ------------- | -------- | ----------------------------------------------------------------------------- |
| `party`       | enum     | **Required.** `supervisory_authority` (Art. 33) or `data_subjects` (Art. 34). |
| `notified_at` | datetime | Defaults to now — record the actual send time for a truthful attestation.     |
| `method`      | string   | Channel used, e.g. `authority_portal`, `email`, `registered_letter`.          |
| `reference`   | string   | Authority case number or data-subject notification batch id.                  |
| `notes`       | string   | Scope and recipients reached.                                                 |

Recording the `supervisory_authority` notification automatically advances a
still-open incident to `notified`. Record both parties when Art. 34 also
applies; the attestation reports each side independently.

***

## The 72-hour attestation

`GET /compliance/breach-incidents/{id}/attestation` returns a
self-contained proof for your compliance binder: the discovery instant, the
computed deadline, each party's notification timestamp, the hours elapsed,
and a `compliant` verdict.

```bash theme={null}
curl https://api.orbit.devotel.io/api/v1/compliance/breach-incidents/breachIncident_9qk2…/attestation \
  -H "X-API-Key: dv_live_sk_..."
```

```json theme={null}
{
  "reference": "BR-2026-0001",
  "status": "notified",
  "discoveredAt": "2026-08-26T15:05:00.000Z",
  "notificationDeadlineAt": "2026-08-29T15:05:00.000Z",
  "supervisoryAuthority": {
    "required": true,
    "notified": true,
    "notifiedAt": "2026-08-27T10:20:00.000Z",
    "hoursAfterDiscovery": 19.25,
    "withinWindow": true,
    "reference": "CASE-2026-11882",
    "method": "authority_portal"
  },
  "dataSubjects": {
    "required": true,
    "notified": true,
    "notifiedAt": "2026-08-28T09:00:00.000Z",
    "hoursAfterDiscovery": 41.92,
    "withinWindow": true,
    "reference": "DSN-2026-31",
    "method": "email"
  },
  "compliant": true,
  "statement": "Incident BR-2026-0001 was reported to the supervisory authority 19.25h after discovery, within the GDPR Art. 33 72-hour window; affected data subjects were notified 41.92h after discovery."
}
```

`compliant` is `true` when notification was not required, or the authority
was notified at or before the deadline. Data-subject notification is
reported alongside but does not gate the flag — the 72-hour clock belongs
to Art. 33. The list endpoint (`GET /compliance/breach-incidents`)
summarises the register with open and overdue counts by severity and
status, so an un-notified incident that has blown its deadline is visible
at a glance.

***

## A worked end-to-end sequence

1. **Open** — `POST /compliance/breach-incidents` with `severity: "high"`.
   The incident opens as `detected`; the 72-hour clock starts at
   `discovered_at`.
2. **Assess** — `PATCH` with `status: "under_assessment"`, refining
   `affected_data_subjects` and `data_categories` as forensics progress.
3. **Contain** — `PATCH` with `status: "contained"` and a `remediation`
   note describing the containment step.
4. **Notify** — `POST …/notifications` with `party: "supervisory_authority"`
   after your DPO files with the authority; the incident moves to
   `notified`. Repeat with `party: "data_subjects"` when Art. 34 applies.
5. **Attest** — `GET …/attestation` and attach the JSON to the binder you
   hand your auditor or the authority.
6. **Close** — `PATCH` with `status: "closed"` once the response is
   complete (blocked until the authority notification is recorded or
   documented as not required).

***

## Storage and limits

Incidents are stored per workspace as a JSONB register, capped at 1000
incidents. Concurrent updates are serialised, so two team members recording
notifications at the same time cannot overwrite one another's timestamps.
When you approach the cap, archive closed incidents out to your evidence
binder to keep the working register lean.

***

## Access control

* Reads (`GET`) — any authenticated member of your workspace.
* Writes (`POST`, `PATCH`) — **owner** and **admin** roles only.
* Every open, update, and notification is written to your audit log with
  the actor and the incident reference.

***

## Related references

* [Data Subject Access Requests (DSAR)](/compliance/dsar) — receiving and
  fulfilling subject requests, the other half of GDPR operations.
* [GDPR Processing Register (ROPA + DPIA)](/compliance/privacy-register) —
  the Art. 30/35 documentation that sits alongside the breach register.
* [Compliance evidence binder](/compliance/evidence-binder) — where the
  attestation and breach counts roll up for an auditor.
* [Assembling a GDPR Posture End to End](/compliance/gdpr-posture-guide) —
  the full sequence the breach register documents one stage of.
* [API Reference → Compliance](/api-reference/endpoints/compliance) — full
  request/response schemas (regenerated from the live API).
