Audit Log

Every mutation in your organization — administrator UI actions and public API calls alike — is recorded in a single audit stream. Use these endpoints to ship that stream into a SIEM, build internal compliance reports, or investigate a specific change. Required scope on the API key: audit-log:read.

Endpoints

MethodPathScopePurpose
GET/api/public/v1/audit-logaudit-log:readPaginated list of audit events with optional filters.
GET/api/public/v1/audit-log/actionsaudit-log:readDistinct action names ever recorded for your org. Useful for building a filter dropdown.

What gets recorded

Public API calls are auto-audited. The entry carries actorRole = "api_key" and actorEmail = "apikey:<apiKeyId>", where <apiKeyId> is the full UUID of the API key that made the call (not the scs_live_… token prefix). Administrator UI actions use the human's email and their org_admin role. The two streams are intermixed in the same log so a single export covers all change history.

List audit events

Returns events newest-first. All filters are optional and may be combined.

GET /api/public/v1/audit-log
  ?action=sarif.ingested
  &actorEmail=apikey:7d8a3e0b-4f12-4cd6-b9e1-21f6cf5d4a73
  &from=2026-05-01T00:00:00Z
  &to=2026-05-29T23:59:59Z
  &page=1
  &pageSize=50
Authorization: Bearer scs_live_…

Query parameters

ParameterTypeDefaultNotes
actionstringExact-match action name. Pull valid values from /audit-log/actions.
actorEmailstringExact-match actor email. For API-key entries use the form apikey:<api-key-uuid>.
fromISO 8601Inclusive lower bound on createdAt (UTC).
toISO 8601Inclusive upper bound on createdAt (UTC).
pageinteger11-based page index.
pageSizeinteger50Capped at 200. Values outside 1–200 fall back to 50.

Response

{
  "items": [
    {
      "id": "0e7a3b4c-9d2f-4e1a-b6c8-2c4f8d5a1e90",
      "createdAt": "2026-05-29T13:42:11.318Z",
      "actorEmail": "apikey:7d8a3e0b-4f12-4cd6-b9e1-21f6cf5d4a73",
      "actorRole": "api_key",
      "action": "assignment.created",
      "targetType": "assignment",
      "targetId": "b1d8c2a0-7e34-4f9a-9d51-8e2c91a4f607",
      "targetLabel": "jane.smith@acme.com / SQL Injection",
      "metadata": "{\"topicId\":\"sql-injection\",\"deadlineDays\":14}",
      "ipAddress": "203.0.113.42"
    },
    {
      "id": "ba98c9d4-5f60-4b21-9c0e-3f72e1b58a44",
      "createdAt": "2026-05-29T13:41:08.902Z",
      "actorEmail": "amelia.ng@acme.com",
      "actorRole": "org_admin",
      "action": "user.invited",
      "targetType": "user",
      "targetId": "c4f1d22a-83b7-4d2c-9a01-7e6b5d1f9c33",
      "targetLabel": "jane.smith@acme.com",
      "metadata": null,
      "ipAddress": "203.0.113.7"
    }
  ],
  "total": 2841,
  "page": 1,
  "pageSize": 50
}
  • metadata is a JSON string (not an object). Parse it on the client; the shape varies per action.
  • total reflects the full filtered count, not just the current page — divide by pageSize to derive page count.
  • User-agent and other request headers are stored server-side for forensics but are not returned in this response.

Example

curl -sS \
  -H "Authorization: Bearer $SCH_API_KEY" \
  "https://api.limeplate.com/api/public/v1/audit-log?from=2026-05-01T00:00:00Z&pageSize=200"

List distinct actions

Returns every action name that has ever been recorded for your organization, sorted alphabetically. The list is org-scoped — a fresh tenant returns an empty array until events start flowing.

GET /api/public/v1/audit-log/actions
Authorization: Bearer scs_live_…

Response

[
  "apikey.created",
  "apikey.revoked",
  "assignment.completed",
  "assignment.created",
  "course.published",
  "sarif.ingested",
  "user.invited",
  "user.role_changed",
  "webhook.created"
]

Example

curl -sS \
  -H "Authorization: Bearer $SCH_API_KEY" \
  https://api.limeplate.com/api/public/v1/audit-log/actions

Shipping to a SIEM

The typical pattern is to poll /audit-log on a cron, passing from equal to the last createdAt you ingested and walking pages until items.length < pageSize. Because results are ordered newest-first, an incremental fetcher should reverse the page before emitting events to keep downstream order chronological. There is no streaming audit webhook in v1 — pair audit polling with the targeted domain webhooks documented under Webhooks when you also need low-latency reaction to specific events.