Incidents (Multi-Clock Hub)
An Incident is a compliance-relevant event that triggers up to
five regulatory deadline clocks in parallel: GDPR Art. 33, EU AI
Act Art. 73, DORA Art. 19, NIS2 Art. 23, and CRA Art. 11. The
Multi-Clock Hub anchors all five clocks to the same incident
record so a single detection event flows into one workflow, not
five. Tested against API version v1. JWT auth on every endpoint;
plan-gated by multiClockIncidents (Governance and above).
The Incident object
| Field | Type | Required | Description |
|---|---|---|---|
_id / id | string | yes | MongoDB ObjectId |
organizationId / workspaceId | string | yes | Tenancy scope |
externalRef | string | no | SIEM ticket / Jira / Linear identifier |
title | string | yes | Operator-readable summary |
summary | string | no | Free-form detail |
severity | enum | no | info, low, medium (default), high, critical |
category | enum | no | data_breach, ai_serious_incident, operational, cyber, product_safety, other |
status | enum | no | open (default), investigating, reported, mitigated, resolved, closed, archived |
triggerTraceIds | string[] | no | Trace IDs that opened the incident |
relatedAgentIds | string[] | no | Agent IDs implicated |
reportedTo | string[] | no | Per-regulator codes the report has reached (gdpr-dpa, aiact-ms, dora-na, nis2-csirt, cra-enisa) |
regulators | Submission[] | no | Per-regulator submission record (code, name, contactEmail, submittedAt, submissionRef) |
createdBy / createdByEmail | string | no | Reporter; email is a snapshot that survives user deletion |
detectedAt | string (ISO 8601) | no | When the event happened (defaults to createdAt); SIEM ingests can pass an earlier value |
closedAt | string (ISO 8601) | no | Set when status transitions to closed |
rootCause / remediation | string | no | Closing-narrative fields |
createdAt / updatedAt | string (ISO 8601) | no | Standard timestamps |
The status enum is a 7-value union spanning both the academic
vocabulary (open → investigating → reported → resolved →
archived) and the dashboard vocabulary (open →
investigating → mitigated → closed). The controller translates
between the two so both call paths see the names they expect.
The IncidentClock object
| Field | Type | Required | Description |
|---|---|---|---|
regulator | enum | yes | gdpr, aiact, dora, nis2, cra |
articleRef | string | no | Free string (e.g., Art. 33) |
clockStartedAt | string (ISO 8601) | yes | When the deadline countdown began |
applicabilityReason | string | no | Why this regulator applies to this incident |
checkpoints | Checkpoint[] | no | Each: label, deadlineAt, completedAt, completedBy, evidenceTraceId, notes |
nextCheckpointAt | string (ISO 8601) | no | Live deadline for the dashboard badge |
finalDeadlineAt | string (ISO 8601) | no | Final regulatory deadline |
status | enum | no | active (default), paused, completed, breached |
A breached checkpoint is not deleted. The clock's status
flips to breached and nextCheckpointAt stays in the past so
the post-incident audit can replay which deadline was missed and
when.
Standard clock cadence
| Regulator | Article | Early | Intermediate | Final |
|---|---|---|---|---|
| GDPR | Art. 33 | — | — | 72 h |
| EU AI Act | Art. 73 | 2 d | 10 d | 15 d |
| DORA | Art. 19 | 4 h | 72 h | 30 d |
| NIS2 | Art. 23 | 24 h | 72 h | 30 d |
| CRA | Art. 11 | 24 h | 72 h | 14 d |
Endpoints
GET /api/v1/incidents
POST /api/v1/incidents
GET /api/v1/incidents/:id
PATCH /api/v1/incidents/:id
POST /api/v1/incidents/:id/close
GET /api/v1/incidents/:id/clocks
POST /api/v1/incidents/:id/clocks/:clockId/checkpoint
POST /api/v1/incidents/:id/checkpoints/:checkpointId/complete
The two checkpoint-completion endpoints share one handler —
the dashboard prefers the second path (cp-N synthetic ids), the
SDK prefers the first (numeric checkpointIndex).
List incidents
GET /api/v1/incidents
| Query parameter | Default | Description |
|---|---|---|
status | — | Filter by status enum |
severity | — | Filter by severity enum |
regulator | — | Filter by attached clock's regulator code |
search | — | Substring on title and summary |
limit | 50 | Page size; capped server-side |
curl "https://api.adjudon.com/api/v1/incidents?status=open&severity=critical" \
-H "Authorization: Bearer $ADJUDON_API_KEY"
import os, requests
r = requests.get(
"https://api.adjudon.com/api/v1/incidents",
params={"status": "open", "severity": "critical"},
headers={"Authorization": f"Bearer {os.environ['ADJUDON_API_KEY']}"},
)
const url = new URL("https://api.adjudon.com/api/v1/incidents");
url.searchParams.set("status", "open");
url.searchParams.set("severity", "critical");
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.ADJUDON_API_KEY}` },
});
Errors: 401, 403 UPGRADE_REQUIRED, 500 INCIDENT_LIST_FAILED.
Create an incident
POST /api/v1/incidents
| Body field | Required | Description |
|---|---|---|
title | yes | Required; non-empty string |
summary | no | Detail |
severity | no | Defaults to medium |
category | no | Defaults to other |
triggerTraceIds | no | Trace IDs that opened the incident |
relatedAgentIds | no | Agents implicated |
regulators | no | Array of regulator codes; clocks attach automatically |
detectedAt | no | Override; defaults to createdAt |
externalRef | no | SIEM/Jira/Linear identifier |
curl -X POST https://api.adjudon.com/api/v1/incidents \
-H "Authorization: Bearer $ADJUDON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Suspicious cross-org trace pattern detected",
"severity": "high",
"category": "ai_serious_incident",
"triggerTraceIds": ["trace_aBcD1234"],
"regulators": [{"code": "aiact"}, {"code": "gdpr"}, {"code": "dora"}]
}'
The response is the full Incident document with embedded clocks
array. Each clock arrives populated with checkpoints for its
regulator's standard cadence (table above). Errors: 400
VALIDATION_ERROR (missing title), 401, 403, 500
INCIDENT_CREATE_FAILED.
Get one incident
GET /api/v1/incidents/:id
Returns the incident with embedded clocks array (each clock
including its checkpoints, computed nextCheckpointAt, and
status). Errors: 401, 403, 404 NOT_FOUND, 500
INCIDENT_GET_FAILED.
Update an incident
PATCH /api/v1/incidents/:id
Partial update; any of title, summary, severity, category,
status, triggerTraceIds, relatedAgentIds, detectedAt,
externalRef may be supplied. Errors: 401, 404, 500
INCIDENT_UPDATE_FAILED.
Close an incident
POST /api/v1/incidents/:id/close
Transitions status to closed and sets closedAt. Body fields
populate the closing narrative the dashboard surfaces:
| Body field | Required | Description |
|---|---|---|
rootCause | no | Short narrative of root cause |
remediation | no | Steps taken |
notes | no | Free-form addendum |
curl -X POST https://api.adjudon.com/api/v1/incidents/65b1f2c4/close \
-H "Authorization: Bearer $ADJUDON_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "rootCause": "Misconfigured policy", "remediation": "Rolled out fix in agents/v1.4.2" }'
A breached clock attached to a closed incident is preserved —
the post-incident audit needs to read which deadlines were
missed. Errors: 401, 404, 500 INCIDENT_CLOSE_FAILED.
List clocks for an incident
GET /api/v1/incidents/:id/clocks
Returns the array of IncidentClock documents attached to the
incident. Useful for a dashboard panel rendering all five
regulator clocks side-by-side. Errors: 401, 404, 500
INCIDENT_CLOCKS_FAILED.
Complete a checkpoint
POST /api/v1/incidents/:id/clocks/:clockId/checkpoint
POST /api/v1/incidents/:id/checkpoints/:checkpointId/complete
| Body field | Required | Description |
|---|---|---|
checkpointIndex | yes (legacy path) | 0-indexed checkpoint number |
evidenceTraceId | no | Decision Hash Chain trace anchoring the report |
evidenceUrl | no (dashboard path) | External URL (Jira ticket, regulator portal receipt) |
notes | no | Free-form addendum |
The dashboard path uses synthetic checkpoint identifiers
(cp-0, cp-1, …); the legacy path takes the numeric
index directly. Both write the same record. Errors: 400
VALIDATION_ERROR (missing index), 401, 404 NOT_FOUND
(incident / clock / checkpoint), 500 CHECKPOINT_COMPLETE_FAILED.
Common gotchas
- Plan-gate. The whole resource is gated by
multiClockIncidents— Sandbox and Scale plans receive403 UPGRADE_REQUIRED. - Two checkpoint paths. Both work, both call the same handler.
New integrations should prefer the dashboard path
(
/checkpoints/:checkpointId/complete); the legacy path is kept for SDK consumers that already integrated againstcheckpointIndex. - Status enum is a union. Seven values cover both the academic vocabulary and the dashboard vocabulary; the controller translates between the two. Don't filter on dashboard-only values when scripting against an academic-vocab system.
- Breached clocks are preserved. A
status: 'breached'clock stays in the index with its missed deadline. Audit replays depend on this.
See also
- Multi-Clock Incidents — the concept page covering five-regulator parallelism in narrative form
- Hash Chain API — the
evidenceTraceIdlinkage anchor - DORA Compliance — Article 19 timing
- EU AI Act Compliance — Article 73 timing
- Audit Log API — where
incident.create,incident.transition, andincident.checkpoint_completeevents land - Error Codes — the full error taxonomy