Admin
Exporting Audit Logs
Download, stream, or archive Alter audit events.
Credential access, provider calls, policy decisions, lifecycle changes, and administrative actions produce structured audit events. The developer portal supports filtered downloads, uncapped bulk jobs, telemetry mirroring, and continuous SIEM delivery. The CLI provides a paginated pull path for custom archives and ingestion pipelines.
What’s in an audit row
Section titled “What’s in an audit row”See Audit logs for the full field list. The short version per call:
- Timestamps, app and provider identifiers, response status, latency.
- Caller (key prefix, agent identity if applicable, free-form
callerattribution). - Principal (user / group / system / agent that owns the grant).
- Grant reference, kind, and data categories when present.
- Context (application-supplied tool name, run ID, thread ID).
- Reason (the human-readable explanation passed on the request).
- Outcome (success / policy denial / provider error / network error).
Sensitive headers are stripped. Audit rows and exports contain request and response metadata (including body sizes), not bodies. Request and response payload capture is a separate, opt-in diagnostic feature: captured bodies use the deployment’s configured size cap (64 KiB per body by default), record truncation, and expire under the configured payload-retention period. Captured payloads are never included in audit exports.
Export paths
Section titled “Export paths”1. Filtered export from the portal
Section titled “1. Filtered export from the portal”On an app’s Audit Logs page, select Export. Choose a date range of up to 365 days, select CSV, JSON, or NDJSON, and decide whether to apply the current view’s filters. The synchronous export contains the 50,000 most-recent matching events. If the cap is reached, the portal reports that the file was trimmed so the range or filters can be narrowed.
2. Bulk export from the portal
Section titled “2. Bulk export from the portal”On the Access & Requests tab, select Bulk export for a server-side job that writes every matching access, request, lifecycle, provisioning, portal and Wallet policy-change event in the selected date range to a downloadable CSV or NDJSON artifact. Bulk exports have no row cap. The portal polls the job and presents a short-lived download link when it is complete. Bulk export requires export storage to be enabled on the deployment, and is available to organization admins only — the control is hidden for other members.
3. Pull via CLI
Section titled “3. Pull via CLI”PAT-authenticated automation can read the audit surface with dashboard_audit:read. The token carries its owner’s audit visibility, re-checked against their live organization role on every request, and the CLI prints a stderr notice when the management plane is narrowed. For example:
alter audit list --since 30d --output jsonl > audit.ndjsonJSON list output returns a paginated envelope; JSONL writes one page of rows. A long-running collector is responsible for advancing --offset or the time window and persisting its own checkpoint.
4. Telemetry endpoint (OTLP)
Section titled “4. Telemetry endpoint (OTLP)”Under Settings → Audit & compliance → Telemetry endpoint (OTLP), configure a default organization collector or app-specific overrides. Alter mirrors audit events as OpenTelemetry spans to the configured OTLP/HTTP collector. This is a telemetry stream, not the compliance source; the authoritative audit trail remains in Alter.
Telemetry and SIEM destinations receive every audit event family the portal’s activity feed shows: credential access, provider calls, approvals, OAuth and managed-secret grant and delegation lifecycle, policy-rule changes made in the portal, the CLI, or by end users in the Wallet, identity-provider provisioning and deprovisioning, and identity events. Legacy Wallet sign-in and navigation records are not exported.
Each span identifies the event and the trace it belongs to separately:
| Attribute / field | Meaning |
|---|---|
alter.event_id | The audit event id — stable across re-delivery |
traceId | The event’s own W3C trace id when the request carried one (alter.trace.origin = source), so the span joins the caller’s distributed trace |
alter.trace.origin = converted | The request’s correlation id was not a W3C trace id; traceId is a deterministic hash of it (events of one request still share a trace) and the original value is in alter.trace.original_id |
alter.trace.origin = event | The event had no correlation id; traceId is derived from the event id, so it never joins another request’s trace |
spanId | The event’s own span id as Alter recorded it (or, when none was recorded, one derived from the event id) — never random, so a re-delivered batch is identical. Wallet configuration events, which record only the request’s span, each get a span derived from their event id |
parentSpanId | The span the event was recorded under: the span of the caller’s request when it sent a traceparent header, or another event’s span, so the event nests in the caller’s trace. Events are not recorded with the caller’s span as their own spanId. Absent when the request carried no traceparent, and for event types recorded without a parent, which appear as root spans. Events recorded before this was enforced may instead carry the caller’s span as their own spanId, with no parent. The recorded ids are also in alter.span.source_id and alter.span.source_parent_id |
alter.app_user_id / alter.caller_app_user_id | The end user the event is about (grant owner or subject), and — on a delegated call — the end user the call was made for |
alter.decided_by_app_user_id | On an approval decision: the approver who decided |
alter.policy_rule_id | The policy rule that decided the event, when a rule did |
alter.resource_type / alter.resource_id | The configuration resource a configuration event changed, such as a policy rule |
alter.causation.id | On deprovisioning events: the id shared by the triggering provisioning event and every grant and delegation revocation it caused |
End users appear by opaque id only; email addresses and display names are never exported. Spans also carry the allowlisted agent-framework context keys the caller sent (alter.context.thread_id, run_id, tool, tool_call_id, tool_bundle, agent, framework, span.name, span.step, span.parent).
5. SIEM destination (OCSF)
Section titled “5. SIEM destination (OCSF)”Configure a SIEM destination under Settings → Audit & compliance → SIEM export in the developer portal. Alter then continuously pushes the organization’s audit events to the SIEM’s HTTPS collector as newline-delimited OCSF 1.5.0 events (Splunk HEC and generic-webhook compatible). Authentication headers for the collector are stored encrypted.
Delivery is at-least-once: a per-destination cursor advances only after the collector acknowledges a batch, so a mid-delivery failure re-sends the batch. SIEMs deduplicate on metadata.uid (the audit event id). An event recorded with a time the cursor has already passed (its record committed after a later one was delivered) is still delivered once, provided it is recorded within an hour of the time it carries. Repeated delivery failures dead-letter the destination — it is auto-disabled and surfaced in the portal, with the cursor preserved so re-enabling resumes without gaps.
CSV and the API
Section titled “CSV and the API”NDJSON exports carry each event exactly as the audit API returns it. CSV flattens the same event into one row per event with fixed columns: nested objects (app, provider, actor, api_key, grant_owner, delegation, end_user, policy) become prefixed columns, the delegation chain becomes one readable step(id) -> step(id) cell, structured records (policy_context, policy_outputs, delegation records, and the full context) are JSON-encoded cells, the deprovisioning causation is flattened into causation_id, causation_trigger, causation_idp_event_id and causation_import_run_id, and an approval decision’s approver is in decided_by_app_user_id. The request’s client address (ip_address) is not included in either format. The one exception is the decision an IP allowlist made: an IP-allowlist denial records the source address the rule evaluated in policy.context.client_ip, because that address is the fact the denial rests on — the same way identity providers and cloud audit logs record the source address of a denied request. It appears wherever the policy context does (the audit API, JSON, NDJSON, and the CSV policy_context cell). SIEM and telemetry streams carry no client addresses at all. Cell values that a spreadsheet would execute as a formula are prefixed with '. Columns added in later releases are appended after the existing ones, so an existing column never changes position.
OCSF event shape (SIEM destination)
Section titled “OCSF event shape (SIEM destination)”Each event delivered to a SIEM destination is an OCSF 1.5.0 API Activity record (class_uid 6003, category_uid 6). It carries identifiers and outcomes only — never tokens and never end-user PII. The identity mapping:
| OCSF field | Meaning |
|---|---|
metadata.version | 1.5.0 |
metadata.uid | Audit event id — the SIEM dedupe key |
time | Event time (epoch milliseconds) |
activity_name | The action performed (for example token.retrieved) |
status_id / status | Outcome enum + caption (Success / Failure / Unknown) |
status_detail | Granular result (success / failure / denied / error) |
severity_id | 1 informational, 3 failure, 4 explicit denial |
actor.user | The acting principal — the approver who decided, on an approval decision (type "User", the end-user id); otherwise the AI agent (type "AI Agent") when one authenticated, the registered caller (type "Other"), the operator for portal and directory-import changes (type "Admin"), or the end user for Wallet policy changes (type "User"); absent when the event has no principal |
actor.app_name / actor.app_uid | The application that made the call |
actor.session.uid | The API key that established the session |
resources[] | The end user the event is about (type "app_user"), the end user a delegated call was made for (type "caller_app_user"), a changed configuration resource such as a policy rule (type "policy_rule"), and, on an approval decision, the agent whose request it was (type "agent") |
metadata.correlation_uid | On deprovisioning events: the id shared by the triggering provisioning event and every revocation it caused |
unmapped | Alter metadata with no first-class OCSF field: event_id, the source trace_id and the otel_trace_id the same event is mirrored under, span ids, policy_decision, the deciding policy_rule_id, actor_source, provider_id, caller_app_user_id, the registered caller actor_id when an agent is the acting principal, and the deprovisioning causation (id, kind, trigger, idp_event_id, import_run_id, idp_id) |
Display names (actor.app_name, actor.user.name) are the names configured in the portal and resolve only within the owning organization; a name that cannot be resolved degrades to the uid alone.
Retention
Section titled “Retention”Audit retention is an organization-wide, admin-only control under Settings → Audit & compliance → Audit retention. The plan defines a minimum and, when applicable, a maximum; the organization override can only extend the plan minimum. Clearing the override returns to the plan minimum. The default plan fallback is 365 days.
A compliance hold prevents matching records from being deleted regardless of the normal retention window. For a separate long-term archive, ingest CLI or bulk-export output into the organization’s storage system.