Skip to content
mittr

Compliance — Audit, Retention, GDPR

Mittr ships three compliance primitives that together let you evidence “who did what, when” for an auditor and respond to a specific end-user’s “show me / delete me” request:

  1. Resource audit log — every state-mutating action (endpoint created, alert paused, API key revoked) on the workspace.
  2. Auth audit log — every authentication-adjacent event (logins, MFA, SAML / OIDC / SCIM, session lifecycle, GDPR job submission).
  3. Data-subject jobs — per-email export and erasure that scan every table referencing the address.

All three respect per-tenant retention windows so storage doesn’t grow unbounded.

Two distinct tables, two distinct shapes:

Resource auditAuth audit
Backing tableaudit_logsauth_audit_logs
RecordsResource state changesAuthentication events
Examplesendpoint.create, alert_rule.disable, api_key.revokepassword.login.fail, mfa.verify.success, sso.login.jit
User IDAlways present (the actor)Nullable (failed logins lack a user)
Subject fieldResource IDIdP subject claim or email
Read APIGET /api/v1/audit-logsGET /api/v1/auth-audit (admin-only)
DashboardAnalytics → ActivityAnalytics → Auth events

Both are tenant-scoped — you can never see another workspace’s rows. Filter pills on each tab let you narrow by resource family or auth event family (e.g. password. matches both .success and .fail).

Each workspace has four independent retention windows, all in days:

ColumnWhat it capsDefault
event_retention_daysDelivered + dead eventsinherit plan default
delivery_attempt_retention_daysPer-attempt rows for those eventsinherit plan default
audit_log_retention_daysResource audit rowsinherit plan default
auth_audit_retention_daysAuth audit rowsinherit plan default

NULL means “fall back to the plan default.” Setting 0 means “keep forever, never purge” — useful for the high-compliance auth trail in regulated environments.

The retention processor runs every hour and applies each tenant’s window per row, so changing a column takes effect on the next cleanup tick (no rebalancing needed).

Set the windows from Settings → Data & Privacy → “Retention” or via the API:

Terminal window
curl -X PATCH https://app.mittr.io/api/v1/me/retention \
-H "Cookie: mittr_session=..." \
-H "Content-Type: application/json" \
-d '{
"eventDays": 90,
"deliveryAttemptDays": 30,
"auditLogDays": 365,
"authAuditDays": 730
}'

Negative values are rejected; values above 7300 (≈20 years) are rejected as a storage DoS guard.

Two flavours, both per-email and admin-only:

Returns every row in the workspace whose payload, audit metadata, or actor field references the given email. Useful for fulfilling “show me my data” requests under GDPR Article 15.

Submit from Settings → Data & Privacy → “Data subject requests” (enter email, click Export) or via the API:

Terminal window
curl -X POST https://app.mittr.io/api/v1/gdpr/data-export \
-H "Cookie: mittr_session=..." \
-H "Content-Type: application/json" \
-d '{"subjectEmail": "[email protected]"}'
# → 202 Accepted, returns {id, kind, subjectEmail, status: "queued"}

The job runs asynchronously (typically completes in seconds for normal data sizes). Poll GET /api/v1/gdpr/jobs/{id} for status; when status: "completed", the dashboard’s Download button links to GET /api/v1/gdpr/jobs/{id}/download. Export blobs are retained for 30 days, then auto-purged.

The export schema is:

{
"schema_version": 1,
"subject_email": "[email protected]",
"client_id": "...",
"exported_at": "2026-04-26T10:00:00Z",
"events": [...],
"delivery_attempts": [...],
"audit_logs": [...]
}

Redacts every event payload referencing the email and deletes matching audit rows. Idempotent — re-running after rows are clean just updates zero rows. Useful for “right to be forgotten” requests under GDPR Article 17.

Terminal window
curl -X POST https://app.mittr.io/api/v1/gdpr/data-erasure \
-H "Cookie: mittr_session=..." \
-H "Content-Type: application/json" \
-d '{"subjectEmail": "[email protected]"}'

What gets touched:

  • events.payload for matching events → replaced with {"_redacted": true, "reason": "gdpr_erasure"} (preserves the delivery row so usage / billing stays consistent).
  • delivery_attempts.response_body for those events → replaced with [redacted: gdpr_erasure].
  • audit_logs rows where actor_id = email or metadata mentions the email → deleted.

What doesn’t:

  • Auth audit rows. Authentication events are tenant-scoped security records, not personal data in the GDPR sense — keep them per your auth_audit_retention_days setting.
  • The user’s users row, if they’re a workspace member. Use Team → Remove member for that.

Every data-subject job emits two auth_audit_logs rows: one at queue time (gdpr.export.queued or gdpr.erasure.queued) and one when the runner finishes (gdpr.{export,erasure}.{completed,failed}). The metadata.job_id field on each row joins them so reviewers can trace request → outcome.

Retention defaults (i.e. what NULL resolves to) come from the workspace’s plan. Feature gates may also restrict who can access auth audit logs, GDPR endpoints, and the per-tenant retention columns; check Settings → Plans for your workspace’s tier.

EndpointMethodAuth
/api/v1/me/retentionGETSession, any role
/api/v1/me/retentionPATCHSession, admin only
/api/v1/auth-auditGETSession, admin only
/api/v1/audit-logsGETSession or API key
/api/v1/gdpr/data-exportPOSTSession, admin only
/api/v1/gdpr/data-erasurePOSTSession, admin only
/api/v1/gdpr/jobsGETSession, admin only
/api/v1/gdpr/jobs/{id}GETSession, admin only
/api/v1/gdpr/jobs/{id}/downloadGETSession, admin only