Skip to content

Compliance API ​

PDPL data retention sweep and SDAIA breach notification reporting.

Per T-06-11: All compliance routes require super_admin role. A middleware check rejects non-super_admin requests with 403 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 ​

RecordEligible whenAction
activationsretainUntil <= now and deletedAt is nullSoft-delete — deletedAt is stamped
esim_store_ordersDeletion was requested, retainUntil <= now, and deletedAt is nullScrub — the eSIM payload columns smdpAddress, matchingId, activationCodeRaw and iccid are nulled, deletedAt is stamped, and the row is kept
notificationsDeletion was requested, retainUntil <= now, and deletedAt is nullClear params to {} and stamp deletedAt. Keep the row, dedupe key, and delivery history
notification_batchesFinished or cancelled at least 24 hours ago, and replayExpiresAt <= now or is null, irrespective of recipient deletionReplace request with channels-only metadata. Keep the batch row, response snapshot, fingerprint, and dedupe history

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.

Account deletion also stamps existing notifications with the same 365-day deadline. Archive and expiry alone do not make recipient notification content eligible. Scrubbed notifications disappear from inbox reads but remain in profile exports with empty parameters. Batch request scrubbing is independent of this recipient retention window; callback receipts and opt-outs are not cleared. See notification retention.

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

json
{
  "sweepDate": "2026-05-05T08:00:00.000Z",
  "prunedCount": 5,
  "mandatedPreservedCount": 42,
  "storeOrdersScrubbedCount": 3,
  "storeOrdersPreservedCount": 17,
  "notificationsScrubbed": 4,
  "notificationsPreserved": 12
}
FieldTypeDescription
sweepDatestringISO 8601 timestamp the sweep evaluated against
prunedCountintegerActivations soft-deleted by this sweep
mandatedPreservedCountintegerActivations still inside their retention window
storeOrdersScrubbedCountintegerStore orders whose eSIM payload was scrubbed by this sweep
storeOrdersPreservedCountintegerStore orders still inside their retention window
notificationsScrubbedintegerNotification records selected for content scrubbing
notificationsPreservedintegerUn-scrubbed notifications with a deletion request and a future retention deadline

The audit event RETENTION_SWEEP_EXECUTED records the sweep timestamp, all six response counts, and notificationBatchRequestsScrubbed (batch requests changed by the sweep). The batch count is audit-only. The retention sweep must run to scrub eligible content; elapsed time alone does not perform the update.

Error Responses ​

CodeStatusCondition
AUTH_REQUIRED401Missing or invalid token
FORBIDDEN403User 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 ​

FieldTypeRequiredDescription
incidentIdstringYesUnique incident identifier
detectedAtstringYesISO 8601 datetime of breach detection
affectedCategoriesstring[]YesArray of affected data categories (min 1)
estimatedAffectedUsersintegerYesEstimated number of affected users (min 0)
mitigationActionsstring[]NoArray of mitigation action descriptions
descriptionstringYesDetailed breach description (min 1 character)

Example Request ​

POST /compliance/breach-report
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
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

json
{
  "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 ​

CodeStatusCondition
AUTH_REQUIRED401Missing or invalid token
FORBIDDEN403User is not super_admin
VALIDATION_ERROR400Invalid request body (missing required fields, etc.)

Internal documentation - Activation System