Skip to content

Audit Events API & Admin UI

Enterprise edition provides comprehensive audit event tracking for compliance, forensic investigation, and observability correlation. All events are correlated via OpenTelemetry trace_id and stored with tenant-isolation for multi-tenant security.

Overview

The audit events API exposes three independent audit streams unified into a single queryable interface:

  • Infrastructure Audit — Operations on deployments, profiles, projects, and configuration
  • Federation Audit — Cross-tenant imports, artifact promotions, and data flows
  • Enterprise Mutations — Admin changes to artifacts, policies, and team assignments

All events include: - Tenant ID (multi-tenant isolation via RLS) - Actor ID (authenticated user or service account) - Trace ID (OpenTelemetry W3C correlation ID for pivoting to traces/logs) - Request ID (UUID fallback for non-span code paths) - Event type and entity references - Structured timestamp (UTC, created_at)

Access Control (RBAC)

All audit endpoints require the audit:read scope, granted to two pre-seeded roles:

Role Scope Notes
enterprise_admin audit:read Full system administrators
auditor audit:read New dedicated auditor role (v0.52.0+)

Assigning the Auditor Role

Via Clerk organization dashboard:

  1. Navigate to Organization SettingsRoles
  2. Assign auditor role to users who need audit access
  3. Verify via GET /api/v1/audit-events — 200 OK confirms permission

Via Enterprise PAT (service-to-service):

curl -H "Authorization: Bearer $PAT_TOKEN" \
  https://your-instance/api/v1/audit-events \
  -H "Accept: application/json"

Cross-tenant access is not permitted in v1. Requests asking for audit events of a tenant other than your own return HTTP 403 Forbidden.

Filter Reference

GET /api/v1/audit-events

Query audit events with flexible filtering. All filter parameters are optional; omitted filters match any value.

curl "https://api.example.com/api/v1/audit-events?event_type=artifact.updated&actor_id=user_123&from=2026-01-01T00:00:00Z&to=2026-12-31T23:59:59Z&limit=50"
Parameter Type Example Description
tenant_id UUID 123e4567-e89b-12d3-a456-426614174000 Filter by tenant (always scoped to your tenant; other tenants rejected)
actor_id UUID user_1a2b3c4d Filter by user or service account
event_type string artifact.updated Event type filter; use /api/v1/audit-events/event-types to list valid values
entity_id UUID artifact_5e6f7a8b Filter by entity (artifact, project, bundle, etc.)
trace_id string (hex) 4bf92f3577b34da6a3ce929d0e0e4736 Filter by OpenTelemetry trace ID (16-byte hex); useful for pivoting to traces
request_id UUID d3c4f5a6-b8e9-4c2d-a1f5-c7d8e9f0a1b2 Filter by request ID (fallback for non-span code paths)
from ISO 8601 2026-05-01T00:00:00Z Start of date range (inclusive)
to ISO 8601 2026-05-31T23:59:59Z End of date range (inclusive)
cursor string eyJjcmVhdGVkX2F0IjogIjIwMjYtMDUtMjUifQ== Pagination cursor (opaque string from previous response)
limit integer 100 Items per page; max 100 (default: 50)

Response Format

{
  "data": [
    {
      "event_id": "d3c4f5a6-b8e9-4c2d-a1f5-c7d8e9f0a1b2",
      "event_type": "artifact.updated",
      "actor_id": "user_1a2b3c4d",
      "tenant_id": "org_5e6f7a8b",
      "entity_id": "artifact_9c1d2e3f",
      "entity_type": "artifact",
      "changes": {
        "name": { "old": "OldName", "new": "NewName" },
        "tags": { "old": ["v1"], "new": ["v1", "stable"] }
      },
      "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
      "request_id": "d3c4f5a6-b8e9-4c2d-a1f5-c7d8e9f0a1b2",
      "created_at": "2026-05-25T14:30:00Z"
    }
  ],
  "cursor": "eyJjcmVhdGVkX2F0IjogIjIwMjYtMDUtMjUifQ=="
}

NDJSON Export

Export all matching audit events as newline-delimited JSON for bulk analysis or compliance archival.

GET /api/v1/audit-events/export

Stream audit events in NDJSON format. All filter parameters from the paginated API apply.

curl -H "Authorization: Bearer $TOKEN" \
  "https://api.example.com/api/v1/audit-events/export?from=2026-01-01&to=2026-12-31" \
  > audit-export-2026.ndjson

# Each line is a valid JSON event object
wc -l audit-export-2026.ndjson

Hard cap: Export is limited to 100k events per request. Larger ranges are rejected with HTTP 413 Payload Too Large. Use narrower date ranges or split by event_type.

Content-Type: application/x-ndjson

Trace Deep-Linking

SkillMeat's audit events include a W3C trace_id field compatible with OpenTelemetry and observability backends. Deep-link from an audit event directly to its distributed trace.

Configuration

Set OBSERVABILITY_TRACE_BACKEND_URL_TEMPLATE environment variable to enable links in the admin UI:

Grafana Tempo (recommended):

OBSERVABILITY_TRACE_BACKEND_URL_TEMPLATE="https://tempo.example.com/explore?traceID={trace_id}"

Jaeger:

OBSERVABILITY_TRACE_BACKEND_URL_TEMPLATE="https://jaeger.example.com/trace/{trace_id}"

Honeycomb:

OBSERVABILITY_TRACE_BACKEND_URL_TEMPLATE="https://ui.honeycomb.io/default/datasets/events/result/{trace_id}"

Datadog:

OBSERVABILITY_TRACE_BACKEND_URL_TEMPLATE="https://app.datadoghq.com/apm/traces/{trace_id}"

Once configured, the admin UI audit detail view displays a View Trace button.

Pre-Cutover Audit Rows

Audit rows emitted before this feature shipped have trace_id: null and request_id: null. Operators can still investigate these events by pivoting to logs via the fallback path:

  1. Note the event's created_at, actor_id, and tenant_id
  2. Query your log backend: tenant_id={X} actor_id={Y} timestamp >= {T-10s} timestamp <= {T+10s}
  3. Correlate on timing and user identity

Fallback path is documented in the admin UI as a tooltip.


References

  • ADR: adr-correlation-and-audit-query.md — Design decisions, trade-offs, and future directions
  • OpenTelemetry Log Data Model: https://opentelemetry.io/docs/specs/otel/logs/data-model/
  • Edition Support: Local edition does not expose audit endpoints (404); Enterprise only
  • Related RBAC: RBAC Architecture Guide