---
id: platform/audit-logs
title: Workspace audit logs
description: Query Bex workspace audit records, follow pagination, interpret callers and outcomes, and investigate changes without confusing audit events with runtime success.
keywords: [bex, audit logs, workspace administration, change history]
last_updated: 2026-09-23
---

Audit logs help a workspace administrator investigate who requested an operation
and which resource it concerned. They complement [application logs](./logging.md),
deployment status, and [notification delivery history](./notifications.md).
They are not application output or a complete record of every runtime event.

## Access and availability

Use a workspace-admin account or an appropriately authorized credential for
that workspace. Knowing another workspace's ID does not grant access to its
audit history. The API requires configured control-plane storage
(`BEX_CP_DB_URI`); an unavailable audit store returns `503`. A caller without
workspace management access receives `403`.

For the example below, use an admin user's authorized OAuth access token as
`BEX_TOKEN` and set `WORKSPACE_ID` to the returned workspace ID. Machine API keys
have the developer role and cannot read audit history. See the
[API permission model](./api.md). Audit records use the owner-scoped route.

## Query a time window

Set `START_TIME` and `END_TIME` to RFC 3339 timestamps for the incident window,
including a timezone, for example `2026-09-05T10:00:00Z`:

```bash
curl --fail-with-body --silent --show-error --get \
  "$BEX_API_URL/v1/owners/$WORKSPACE_ID/audit-logs" \
  -H "Authorization: Bearer $BEX_TOKEN" \
  --data-urlencode "startTime=$START_TIME" \
  --data-urlencode "endTime=$END_TIME" \
  --data-urlencode 'direction=backward' \
  --data-urlencode 'limit=50'
```

`backward` returns newest records first; `forward` returns oldest first. Omitted
direction defaults to newest first. Invalid time or direction values are errors,
not requests for an unfiltered history.

The response is an array of `{auditLog, cursor}` entries. To continue, pass the
last returned cursor as `cursor` and preserve the same time window and direction.
Continue until no further entries are returned.

The REST query supports time bounds, direction, cursor, and limit. If you need
to narrow by actor, resource, or event, filter the returned records in your
analysis.

## Interpret a record

| Field | Meaning in Bex |
| --- | --- |
| `id`, `timestamp` | Record identity and event time; timestamps are returned in UTC. |
| `event` | A mapped Render-style event name where supported, otherwise a Bex operation name. |
| `status` | `success` for an allowed audit outcome, or `error` for a denied outcome. |
| `actor` | Caller type and, when available, its subject ID. Email is not included. |
| `metadata` | String-valued details such as the target, changed role, or maintenance setting. |
| `resource` | Bex's authorization resource reference, when available. |

`actor.type` is `user` for a browser session, `rest_api` for an OAuth bearer, or
`system` for other/unattributed callers. A bearer may represent an API key or an
OAuth client; inspect available subject and OAuth metadata rather than assuming
it identifies a particular human. Missing actor details are not evidence that
an operation was harmless.

A denied operation is exposed as `status: error` with
`metadata.outcome: denied`. Conversely, **`status: success` is not proof that a
deployment, job, or database operation finished successfully**. Check the
resource's resulting state. Event coverage and timing depend on the operation;
do not treat the log as an exhaustive transaction journal.

## Investigate a change

1. Record the affected resource ID and an incident window in UTC.
2. Query and paginate the workspace audit history for that window.
3. Compare actor, target, event, and available change metadata. For maintenance
   events, the `to` value helps distinguish enabling from disabling.
4. Check the service, deployment, or [one-off job](./one-off-jobs.md) state and
   relevant logs to establish what actually happened.
5. Apply the appropriate recovery procedure, then verify the application or
   data result independently of the audit entry.

Keep exported audit data in an access-controlled location. The records omit
credential bodies, but caller IDs, resource names, and authorization metadata
can still be sensitive.

## Retention and missing records

The default retention is 90 days. An installation operator can configure
`BEX_AUDIT_RETENTION_DAYS`; the retention worker purges older records at startup
and on its daily sweep. Confirm your installation's retention before relying on
historical availability, and export records you need before they expire.

For missing records, check the workspace, time bounds, pagination, permissions,
configured store, and retention window. Confirm that the operation emits an
audit event; application requests and background activity are not universally
audited. Use resource status and runtime logs alongside this history.
