Aira

DORA incident reporting (Articles 17-19)

How Aira models the DORA incident lifecycle — detection, classification, resolution, and Article 19 ESA-submission PDFs signed with Ed25519.

DORA Articles 17–19 govern the full ICT-incident lifecycle:

  • Article 17 — internal incident management process
  • Article 18 — classification by severity, category, and impact
  • Article 19 — mandatory reporting of major incidents to the relevant European Supervisory Authority within tight initial, intermediate, and final deadlines

Aira models this as a four-state lifecycle with an auditable transition per step.

Incident states

detected  →  classified  →  resolved  →  reported
StateTransition
detectedPOST /dora/incidents — opens the record with title, description, timestamp, and operational impact
classifiedPUT /dora/incidents/{uuid}/classify — sets severity, category, optional root-cause details
resolvedPUT /dora/incidents/{uuid}/resolve — post-mortem summary + lessons learned
reportedGET /dora/incidents/{uuid}/report — generates the signed PDF (auto-promotes the state)

Classification

Severity is one of critical, high, medium, low. Category is one of:

ValueMeaning
cyber_attackExternal malicious activity (ransomware, DDoS, intrusion)
system_failureInternal failure (DB, infra, dependency)
third_party_failureAn ICT third party caused the incident — third_party_uuid is required
data_breachConfidentiality-impacting incident
operational_errorHuman or procedural error
otherNone of the above

An incident is automatically promoted to is_major=True when severity is critical or high. You can also override this explicitly via the is_major field on the classify request.

Root cause

Optional on classify, typically populated at resolve-time:

  • root_cause_summary — free-text narrative
  • root_cause_classification — one of software_bug, configuration_error, human_error, malicious_attack, third_party_issue, infrastructure_failure, unknown

Article 19 — the ESA submission

Only major incidents produce a PDF. The report contains seven sections:

  1. Summary — title, timestamps, clients affected
  2. Classification — severity, category, major flag
  3. Timeline — detected / classified / resolved / reported
  4. Impact — affected services, geographic scope, client count
  5. Root cause analysis — classification + narrative
  6. Resolution — summary + lessons learned
  7. Linked Aira receiptsrelated_action_uuids with their cryptographic hashes

The PDF is signed with the same Ed25519 key used for action receipts and EU AI Act reports. Auditors can verify the signature offline against the public JWKS at /.well-known/jwks.json.

Aira does not submit the report to the ESA for you — that transmission goes through your regulator's portal (e.g. the BaFin MVP reporting system). The signed PDF is the evidence you upload.

Example

from aira import Aira

client = Aira(api_key="aira_live_...")

# Step 1: detect
incident = client.create_dora_incident(
    title="Core banking DB unavailable",
    description="Primary Postgres cluster rejected connections for 23 min.",
    detected_at="2026-04-15T10:00:00Z",
    clients_affected_count=42000,
    affected_services=["core-banking", "mobile-app"],
)

# Step 2: classify (auto-promotes to major at severity=critical)
client.classify_dora_incident(
    incident.uuid,
    severity="critical",
    category="system_failure",
    root_cause_classification="infrastructure_failure",
    root_cause_summary=(
        "Synchronous replication to standby broke during a disk-"
        "pressure event on the primary; standby refused writes."
    ),
)

# Step 3: resolve
client.resolve_dora_incident(
    incident.uuid,
    resolution_summary="Failover to standby completed at 10:23. Primary rebuilt by 11:14.",
    lessons_learned="Add disk-pressure monitor that triggers failover preemptively.",
)

# Step 4: download signed PDF for ESA submission
pdf = client.download_dora_incident_report(incident.uuid)
open(f"dora-{incident.uuid}.pdf", "wb").write(pdf)
import { Aira } from "aira-sdk";

const aira = new Aira({ apiKey: "aira_live_..." });

const incident = await aira.createDoraIncident({
  title: "Core banking DB unavailable",
  description: "Primary Postgres cluster rejected connections for 23 min.",
  detectedAt: "2026-04-15T10:00:00Z",
  clientsAffectedCount: 42000,
  affectedServices: ["core-banking", "mobile-app"],
});

await aira.classifyDoraIncident(incident.uuid, {
  severity: "critical",
  category: "system_failure",
  rootCauseClassification: "infrastructure_failure",
  rootCauseSummary:
    "Synchronous replication to standby broke during a disk-pressure event.",
});

await aira.resolveDoraIncident(incident.uuid, {
  resolutionSummary: "Failover to standby completed at 10:23.",
  lessonsLearned: "Add disk-pressure monitor that triggers failover preemptively.",
});

const pdf = await aira.downloadDoraIncidentReport(incident.uuid);

Verification

The PDF carries three pieces of evidence:

  • report_content_hash — SHA-256 of the canonical PDF bytes
  • report_signature — Ed25519 signature over the content hash
  • report_signing_key_id — the JWKS key ID used

An external auditor can verify without any Aira client by downloading the public key from /.well-known/jwks.json and running a standard Ed25519 check.

On this page