All Docs
FeaturesCalmony Sanctions MonitorUpdated March 12, 2026

Audit Logging

Audit Logging

The platform maintains an immutable audit log of all significant operations, including state-changing actions and every read of sensitive PII fields. The audit log supports SOC 2 Type II compliance (CC6.1, CC6.3) and GDPR Article 20 obligations.


Audit Actions Reference

PII Read Access (SOC 2 CC6.1 / CC6.3)

Added in v0.1.128.

ActionDescription
person.accessedAn individual person record was read, exposing dateOfBirth, nationality, and registrationNumber
export.accessedA bulk export of screening data, people records, or the audit trail was downloaded

person.accessed — Metadata Fields

{
  "fullName": "Jane Smith",
  "fieldsAccessed": ["dateOfBirth", "nationality", "registrationNumber"],
  "matchCount": 3,
  "via": "rest_api_v1"   // present only for external REST API v1 calls
}

export.accessed — Metadata Fields

For people exports (/api/export/people):

{
  "format": "csv",
  "recordCount": 42,
  "exportType": "people_list",
  "fieldsExported": ["fullName", "dateOfBirth", "nationality", "registrationNumber", "status"]
}

For screening history exports (/api/export/screening-history):

{
  "format": "csv",
  "peopleCount": 42,
  "matchCount": 18,
  "reviewCount": 12,
  "exportType": "screening_history",
  "fieldsExported": ["personName", "sanctionedEntityName", "confidenceScore", "matchAlgorithm", "reviewDecisions"]
}

For audit trail exports (/api/export/audit-trail):

{
  "format": "csv",
  "recordCount": 500,
  "exportType": "audit_trail"
}

Dual-Log Pattern for Exports

All export endpoints write two audit entries per request:

  1. export.accessed — records the SOC 2 access event (CC6.1/CC6.3)
  2. gdpr.data_exported — records the GDPR Article 20 portability event

Both entries are written in sequence before the response is returned. If either write fails, the failure is swallowed silently — audit errors never interrupt or fail the main data response.


Endpoints That Emit PII Read Audit Entries

EndpointAudit ActionNotes
GET /api/people/[id]person.accessedInternal Next.js app
GET /api/v1/people/[id]person.accessedExternal REST API v1; includes via: "rest_api_v1"
GET /api/export/peopleexport.accessed + gdpr.data_exportedBulk export
GET /api/export/screening-historyexport.accessed + gdpr.data_exportedBulk export
GET /api/export/audit-trailexport.accessed + gdpr.data_exportedBulk export

Compliance Coverage

RequirementControls MetMechanism
SOC 2 Type IICC6.1, CC6.3person.accessed and export.accessed audit entries
GDPR Article 20Data portability logginggdpr.data_exported audit entries (unchanged)

Implementation Notes

  • All audit writes use writeAuditLogWithRequest, which automatically extracts ipAddress and userAgent from the incoming request
  • Audit log entries are immutable — there is no update or delete path
  • A failed audit write will not cause the endpoint to return an error; the main response is always returned