Audit Log
The Audit Log is the append-only record of who did what in your tenant: sign-ins and failed sign-ins, changes to users, roles and groups, API keys and connector credentials, configuration that reached production, data exports and downloads, and deletions. It is the evidence you hand an auditor, and the stream your security team can forward into a SIEM.
The Audit Log is a tab of the Security page, under Manage in the sidebar. It is available to tenant administrators, to the built-in Security Auditor role (see Security) and to any custom role that carries the security_log.view grant. Exporting the log and configuring forwarding need security_log.export as well, so a compliance reviewer can read without being able to bulk-extract staff activity.
Reading or exporting the log is itself recorded.
What is recorded
Every record answers who, what, when, where from, on what, and what changed. Events are grouped in six categories:
| Category | Examples |
|---|---|
| Authentication and session | auth.login.succeeded, auth.login.failed (with the reason), auth.login.blocked, auth.logout, auth.session.expired, auth.session.revoked (with the reason: user_deactivated, password_reset, or revoked_by_admin from the Sessions tab), auth.password.changed, auth.password.reset_completed, auth.tenant.switched |
| Identity and access | iam.user.invited, iam.user.deactivated, iam.role.assigned, iam.role.revoked, iam.role_definition.updated (with the grants added and removed), iam.group.membership_changed |
| Credentials and secrets | credential.api_key.issued, credential.api_key.revoked, credential.api_key.rejected, credential.connector.created, credential.capture_token.issued |
| Configuration | config.project.published (with the full changeset), config.project.version_deleted, config.models.updated, config.budget.updated, config.retention.updated, config.tenant_settings.updated, config.security_log_forwarding.updated, config.security_notifications.updated |
| Data access and egress | data.document.viewed, data.api.read, data.export.executed, data.document.downloaded, data.bulk_download, data.security_log.viewed, data.security_log.exported |
| Destructive and administrative | admin.transaction.deleted, admin.document.deleted, admin.project.deleted, admin.dataset.deleted, admin.memory.wiped, admin.transaction.rerun, admin.action (any platform-operator action) |
The full vocabulary, with a one-line description of each type, is served by the API at GET /security-log/event-types and shown in the page's event type filter. Event type names are stable: a name is never renamed or reused, so rules written against them keep working.
The audit boundary is publish
Editing a field, a prompt, a rule or a workflow step in the designer is ordinary project work and affects nothing in production, so it is not a security event. The moment configuration starts governing production is publish, which is recorded as config.project.published together with the same changeset the publisher was shown in the confirmation dialog. Settings that take effect immediately, outside the publish cycle (tenant settings, AI models, budgets, retention), each have their own event.
Who looked at a document
data.document.viewed answers the question a breach investigation starts with. It is written when a person opens a transaction in the viewer, whichever way they got there (the work queue, a link, evaluation, the memory pages, the embedded viewer), once per person, transaction and hour: the session is recorded, not every page scrolled. Thumbnails in the transaction list do not count as a view.
Reads through the API are aggregated instead: data.api.read is one record per API key per hour with the number of requests, the transactions touched (the first 200 listed, the rest counted) and the addresses they came from. Downloads and exports are always recorded individually.
What is never recorded
Passwords and password hashes, reset and session tokens, API keys, connector passwords, document content, OCR text and extracted field values are never written to the log. Where a configuration change touches a secret, the record shows ***. Where a published changeset contains free text such as a prompt, the record carries a content hash and a length rather than the text.
Using the page
- Filters: a date range (the last 30 days by default), a category or a single event type, outcome (success, denied, failed), source (web, API, CLI, Copilot, connector, system), the actor's email, and a target id. The range can cover up to 400 days.
- Rows expand to the full record: the request id that joins it to the application logs, the user agent, the roles the actor held at the time, and the structured changes. A publish record offers Load full changes for the complete changeset.
- Export downloads the current filter as CSV or as JSON Lines. The JSON form is the stored record, byte for byte the same shape forwarding sends.
- Columns can be sorted, resized, reordered and hidden; the layout is remembered per user.
- A transaction's Activity Log (the clock icon on a transaction) links to the audit records for that transaction, for anyone who can read the log: who viewed, downloaded, exported, re-ran or deleted it.
The actor is always the person. When the Copilot assistant performs an action on someone's behalf, the record names the person as the actor and Copilot as the source, with the conversation id in the record so the instruction behind the action can be retrieved.
Retention
Records are kept for 400 days by default, long enough to cover a 12-month audit window and the audit itself. The value is shown on the page and set by the platform operator; a tenant administrator cannot shorten it. Lowering retention never removes existing records early: each day's records age out under the retention that was in force when they were written.
Audit retention is independent of transaction retention: the record of who exported a transaction outlives the transaction.
No one can delete individual records. The only removal is the daily sweep dropping whole expired days.
Forwarding to a SIEM
Forwarding (on the page, with security_log.export) pushes every new record to an HTTPS endpoint of yours as JSON batches, signed with a shared secret. Splunk HTTP Event Collector, Microsoft Sentinel and Elastic all ingest this format directly.
| Setting | Meaning |
|---|---|
| Webhook URL | Your receiver. Must be reachable over HTTPS; private and loopback addresses are refused unless the deployment allows them. |
| Signing secret | Stored encrypted. Each batch carries X-DocAI-Signature: sha256=<hex>, the HMAC-SHA256 of the request body with this secret. |
| Event types to forward | Optional prefixes such as auth., iam., credential.; empty forwards everything. |
| Records per batch | 1 to 1000, default 200. |
Forwarding starts from the moment it is enabled; earlier history is available through Export. Delivery is at least once: a batch that is not acknowledged with a 2xx is retried with backoff, so your receiver should de-duplicate on event_id. Send test posts an empty signed batch so you can verify the receiver and the signature before enabling.
Batch body:
{
"event": "security_log.batch",
"schema_version": 1,
"tenant_id": "…",
"batch_id": "…",
"sent_at": "2026-09-11T09:14:22.318Z",
"records": [ { "...": "one stored record per entry, see below" } ]
}
Notifications
A few events are worth an email even without a SIEM. The set is fixed and small on purpose; anything beyond it is a rule in your SIEM over the forwarded stream.
| Event | Who is emailed |
|---|---|
| An account is blocked after repeated failed sign-ins | Tenant administrators, at most once per account per hour |
| A role's grants change | Tenant administrators |
| A role that can manage the tenant, assign roles or export the audit log is assigned | Tenant administrators |
| An API key is issued | Tenant administrators |
| Audit log retention changes | Tenant administrators and the platform operator |
| The audit log is exported | Tenant administrators other than the person who exported it |
"Tenant administrators" means everyone who holds the tenant.manage grant in the tenant, through whichever role, plus any extra addresses a tenant administrator added on the Security page (Overview, then Configure notifications), where the emails can also be turned off for the tenant; see Security: Notifications. Each email names the actor, the time, the source address and the record id, and links to this page. Nothing is sent when the deployment has no mail server. The platform operator address and its switch (System Settings, Security) cover only the emails addressed to the operator.
Sign-in protection
Sign-in is throttled per account and per source address. After 5 failed attempts on one account in 15 minutes each response is delayed (2 seconds, doubling to 30); after 20 the account is blocked for 15 minutes, then the counter clears. The address counter works the same way at 20 and 100, so an office sharing one address is not locked out by a few mistyped passwords. A block is temporary, never touches existing sessions, and is recorded as auth.login.blocked. The platform operator can clear a block early, which is recorded as auth.login.unblocked.
Record format
One JSON object per record. Field names are stable; schema_version increments if the shape ever changes so an ingest pipeline can tell.
{
"event_id": "evt_1757581462318_a1b2c3d4e5f6",
"schema_version": 1,
"timestamp": "2026-09-11T09:14:22.318Z",
"event_type": "iam.role_definition.updated",
"outcome": "success",
"actor": {
"kind": "user",
"user_id": "…",
"email": "alice@customer.com",
"display_name": "Alice Chen",
"auth_method": "password",
"roles": ["admin"]
},
"channel": {
"source": "web",
"client": null,
"ip": "203.0.113.7",
"user_agent": "Mozilla/5.0 …",
"request_id": "8f3c0a1e2b4d5c6f",
"api_key_id": null,
"path": "PATCH /auth/roles/definitions/{role_id}"
},
"tenant_id": "…",
"target": {
"type": "role_definition",
"id": "…",
"label": "Invoice Reviewer",
"project_id": null
},
"changes": {
"grants_added": ["transaction.delete"],
"grants_removed": [],
"renamed": null
},
"reason": null,
"has_details": false,
"changes_truncated": false
}
| Field | Meaning |
|---|---|
event_id | Unique, time-ordered id. Use it to de-duplicate forwarded batches. |
timestamp | UTC, ISO 8601, millisecond precision, from the server clock. |
event_type | One of the stable names above. The prefix before the first dot is the category. |
outcome | success, denied (the caller was not allowed) or failed (the action could not complete, for example a wrong password). Denied attempts are recorded with the same detail as successes. |
actor | Who. kind is user, api_client, platform_admin, system or anonymous (a failed sign-in). roles are the roles held at the time. |
channel | Where from. source is web, api, cli, assistant, connector or system; ip is the client address as seen behind the deployment's trusted proxies; request_id matches the application log line for the same request; Copilot actions add conversation_id. |
target | On what. label is captured when the record is written, so a deleted user or project still reads by name a year later. |
changes | What changed, structured per event type. |
reason | Why an attempt failed or was denied. |
has_details | A larger companion document exists (a publish changeset); the page loads it on demand. |
changes_truncated | changes was too large for one record and moved to the details document. |
API
| Endpoint | Grant | Purpose |
|---|---|---|
GET /security-log | security_log.view | Query the tenant's stream, newest first, cursor-paginated. Filters: from, to, event_type (prefix), actor_email, actor_user_id, actor_kind, target_type, target_id, target_project_id, outcome, source, ip, cursor, limit. A query may span 400 days; an export may span the full retention. |
| `GET /security-log/export?format=csv | json` | security_log.export |
GET /security-log/event-types | security_log.view | The vocabulary. |
GET /security-log/{event_id}/details | security_log.view | The details document of one record. |
GET /security-log/retention | security_log.view | The effective retention, read-only. |
GET, PUT /security-log/forwarding; POST /security-log/forwarding/test | security_log.export | Forwarding configuration. |
The same endpoints accept an API key with the matching grants. Platform operators read the deployment-level stream with the da admin audit commands.
What the log cannot show
The log records every action taken through the application, by any channel. A read of the storage account through the cloud provider's own data plane does not pass through the application and cannot appear here; the evidence for that path is the platform's own diagnostic logging (storage diagnostic logs, identity sign-in logs), which self-hosted and managed deployments control themselves.