API Reference
Audit Log

Audit Log

The audit log records who did what, and when, across the org - offboarding actions, integration changes, exports, and administrative changes. Entries are hash-chained (each entry's hash covers the previous entry's hash), so tampering with or deleting a row breaks the chain and can be detected.

These endpoints sit under /api/audit-log and use your regular dashboard session, not an API key. Access is role-based: viewing and exporting require superadmin, admin, or hr.


List audit log entries

GET /api/audit-log

Query parameters

ParamTypeDescription
limitintegerResults per page (default 50, max 100)
offsetintegerRow offset for pagination (default 0)
actionstringFilter by exact action name
actorIdUUIDFilter by the user who performed the action
fromdateOnly entries created on or after this date
todateOnly entries created on or before this date
searchstringMatches against target, details, or actor name

Response 200 OK

{
  "rows": [
    {
      "id": "9e1c2f3a-...",
      "action": "offboarding_stage_changed",
      "target": "Jordan Lee",
      "details": "Stage changed from notice_period to it_revocation",
      "created_at": "2024-06-02T14:30:00.000Z",
      "is_signed": true,
      "actor": { "id": "usr_abc123", "full_name": "Jane Smith" }
    }
  ],
  "total": 1480,
  "limit": 50,
  "offset": 0
}

is_signed just reflects whether the row has a hash recorded - it doesn't tell you whether the chain around it is intact. Use /verify for that.


Export the audit log

GET /api/audit-log/export

Exports up to 5,000 matching rows. Rate-limited to 10 exports per 15 minutes per org.

Query parameters - same filters as the list endpoint, plus:

ParamTypeDescription
formatstringcsv (default) or json

Response - a file download. CSV columns are ID, Timestamp, Actor, Action, Target, Details, Entry Hash, Prev Hash. The JSON format returns { "exported_at": "...", "rows": [...] } with each row's hash chain fields included.

Both formats include an X-Content-Digest: hmac-sha256=<digest> response header - an HMAC of the exported body, computed server-side, so you can confirm the file wasn't altered after it left PurpletGo.

The export itself is logged as an audit_log_exported entry.


Verify chain integrity

GET /api/audit-log/verify

Requires the tamper-evident audit log feature (Enterprise). Rate-limited to 2 requests per minute per org.

Query parameters

ParamTypeDescription
limitintegerMax entries to check (default 10000, max 50000)

Response 200 OK

{
  "ok": true,
  "checked": 1480,
  "broken": []
}

If any link in the chain has been tampered with, ok is false and broken lists the affected entries. Every verification run is itself written back to the audit log as audit_chain_verified.


Retention settings

GET /api/audit-log/retention · PUT /api/audit-log/retention

Superadmin only. Controls how many months of audit history the org retains.

{ "audit_retention_months": 24 }

PUT accepts a value between 3 and 120 and requires the tamper-evident audit log feature.


Archives

GET /api/audit-log/archives · POST /api/audit-log/archive

Enterprise orgs can archive their full audit log to Google Cloud Storage - either on a schedule (handled internally) or on demand via POST /archive (superadmin only, rate-limited to 4 per hour, requires AUDIT_ARCHIVE_BUCKET to be configured for the deployment).

GET /archives lists past archive runs:

{
  "archives": [
    {
      "id": "b2c3d4e5-...",
      "gcs_path": "gs://purpletgo-audit-archives/audit-logs/org_id/2024-06-01T00-00-00-000Z.json",
      "file_digest": "hmac-sha256=...",
      "row_count": 48213,
      "from_ts": "2023-01-01T00:00:00.000Z",
      "to_ts": "2024-06-01T00:00:00.000Z",
      "is_auto": true,
      "created_at": "2024-06-01T00:05:00.000Z",
      "exported_by_name": null
    }
  ]
}

POST /archive returns the newly created archive record in the same shape.


Related

  • Webhooks - subscribe to audit.created instead of polling
  • Reports - the compliance summary and SLA export endpoints