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:
- Navigate to Organization Settings → Roles
- Assign
auditorrole to users who need audit access - 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):
Jaeger:
Honeycomb:
OBSERVABILITY_TRACE_BACKEND_URL_TEMPLATE="https://ui.honeycomb.io/default/datasets/events/result/{trace_id}"
Datadog:
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:
- Note the event's
created_at,actor_id, andtenant_id - Query your log backend:
tenant_id={X} actor_id={Y} timestamp >= {T-10s} timestamp <= {T+10s} - 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