Compliance API
PDPL data retention sweep and SDAIA breach notification reporting.
Per T-06-11: All compliance routes require
super_adminrole. A middleware check rejects non-super_admin requests with403 FORBIDDEN. Per T-06-12: Every sweep and report invocation is audit-logged.
POST /compliance/retention/sweep
Execute a PDPL data retention sweep. Records whose retention deadline is at or before the sweep time (retainUntil <= now) are processed; records with a later deadline (retainUntil > now) remain mandated, are preserved, and are counted.
Requires authentication + super_admin role.
What the sweep does
| Record | Eligible when | Action |
|---|---|---|
activations | retainUntil <= now and deletedAt is null | Soft-delete — deletedAt is stamped |
esim_store_orders | Deletion was requested, retainUntil <= now, and deletedAt is null | Scrub — the eSIM payload columns smdpAddress, matchingId, activationCodeRaw and iccid are nulled, deletedAt is stamped, and the row is kept |
Store orders are scrubbed rather than removed because the order and its payment are a financial record. Everything with financial meaning stays: the presentment amount and currency, the FX rate, the retail USD snapshot, the product link, and the timestamps. A scrubbed order still appears in GET /store/orders with esimProfile: null, and its QR endpoint returns 404 STORE_ORDER_NOT_FOUND.
retainUntil is stamped on a user's store orders when that user requests account deletion through DELETE /profile. The retention window is 365 days per CMPL-05.
The deadline comparison is inclusive: a record whose retainUntil timestamp exactly equals the sweep's now value is eligible in that sweep. The same conditions — retainUntil <= now and deletedAt is null — are applied when selecting and marking/scrubbing, so an eligible record is counted and processed once; records with retainUntil > now remain mandated.
Example Request
POST /compliance/retention/sweep
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Response
200 OK
{
"sweepDate": "2026-05-05T08:00:00.000Z",
"prunedCount": 5,
"mandatedPreservedCount": 42,
"storeOrdersScrubbedCount": 3,
"storeOrdersPreservedCount": 17
}| Field | Type | Description |
|---|---|---|
sweepDate | string | ISO 8601 timestamp the sweep evaluated against |
prunedCount | integer | Activations soft-deleted by this sweep |
mandatedPreservedCount | integer | Activations still inside their retention window |
storeOrdersScrubbedCount | integer | Store orders whose eSIM payload was scrubbed by this sweep |
storeOrdersPreservedCount | integer | Store orders still inside their retention window |
The audit event RETENTION_SWEEP_EXECUTED records all five values.
Error Responses
| Code | Status | Condition |
|---|---|---|
AUTH_REQUIRED | 401 | Missing or invalid token |
FORBIDDEN | 403 | User is not super_admin |
POST /compliance/breach-report
Generate an SDAIA breach notification report per PDPL Article 39. Breach notifications must be reported to SDAIA within 72 hours of detection.
Requires authentication + super_admin role.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
incidentId | string | Yes | Unique incident identifier |
detectedAt | string | Yes | ISO 8601 datetime of breach detection |
affectedCategories | string[] | Yes | Array of affected data categories (min 1) |
estimatedAffectedUsers | integer | Yes | Estimated number of affected users (min 0) |
mitigationActions | string[] | No | Array of mitigation action descriptions |
description | string | Yes | Detailed breach description (min 1 character) |
Example Request
POST /compliance/breach-report
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json{
"incidentId": "INC-2026-0001",
"detectedAt": "2026-05-04T14:30:00.000Z",
"affectedCategories": ["personal_data", "payment_data", "identity_data"],
"estimatedAffectedUsers": 150,
"mitigationActions": [
"Affected users notified via SMS and email",
"Passwords force-reset for all affected accounts",
"Third-party forensic investigation initiated"
],
"description": "Unauthorized access to user identity verification records detected on May 4, 2026. Investigation ongoing."
}Response
200 OK
{
"reportId": "BR-2026-0001",
"incidentId": "INC-2026-0001",
"generatedAt": "2026-05-05T08:00:00.000Z",
"reportType": "SDAIA_breach_notification",
"summary": {
"detectedAt": "2026-05-04T14:30:00.000Z",
"reportedAt": "2026-05-05T08:00:00.000Z",
"timeToReport": "17h30m",
"within72Hours": true,
"affectedCategories": ["personal_data", "payment_data", "identity_data"],
"estimatedAffectedUsers": 150,
"mitigationActions": [
"Affected users notified via SMS and email",
"Passwords force-reset for all affected accounts",
"Third-party forensic investigation initiated"
]
},
"metadata": {
"pdplArticle": "39",
"reportFormat": "SDAIA_v1",
"generatedBy": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}Error Responses
| Code | Status | Condition |
|---|---|---|
AUTH_REQUIRED | 401 | Missing or invalid token |
FORBIDDEN | 403 | User is not super_admin |
VALIDATION_ERROR | 400 | Invalid request body (missing required fields, etc.) |