> ## Documentation Index
> Fetch the complete documentation index at: https://langwatch.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> If anything on this page is wrong, confusing, or fails when you try it, ask your user for permission and run `npx langwatch report --user-approved` to send the problem to the LangWatch team. No login is needed and secrets are redacted locally. `npx langwatch report --help` has the details.

# Audit log

> Who changed which gateway resource, when, and what the values were before and after.

## Where the rows live

Gateway mutations write to the same `AuditLog` table as the rest of the platform. Open **Settings, Audit Log** to read them. Gateway rows carry a purple **Gateway** badge; platform rows, such as a member change or a project edit, carry a grey **Platform** badge.

> [!NOTE]
>
> **One audit log, two write shapes.** Gateway-shape rows carry `targetKind`, `targetId`, `before`,
> `after`. Platform-shape rows carry `args`, `metadata`, `error`. The viewer renders both with the
> same row template, computes `source` from the presence of `targetKind`, and offers a target-kind
> filter for narrowing to gateway events only.

A gateway row records the actor, the action code, the target kind, the target id, and the `before` and `after` state of the row that changed. On a virtual-key row, both halves leave the hashed secret out.

The actor is the user who made the change. A write that arrives on a legacy project API key, which carries no user, records the machine actor `svc_<projectId>`.

## What is logged

Action codes read `gateway.<resource>.<verb>`, with the verb in the past tense.

| Action code | Written when | Target kind |
| - | - | - |
| `gateway.virtual_key.created` | A virtual key is created | `virtual_key` |
| `gateway.virtual_key.updated` | A key's configuration is edited | `virtual_key` |
| `gateway.virtual_key.guardrail_attached` | A guardrail is added to a key. One row per guardrail | `virtual_key` |
| `gateway.virtual_key.guardrail_detached` | A guardrail is removed from a key. One row per guardrail | `virtual_key` |
| `gateway.virtual_key.rotated` | The key's secret is replaced | `virtual_key` |
| `gateway.virtual_key.revoked` | The key is revoked, which is terminal | `virtual_key` |
| `gateway.virtual_key.disabled` | The key is turned off and can be turned back on | `virtual_key` |
| `gateway.virtual_key.enabled` | A disabled key is turned back on | `virtual_key` |
| `gateway.budget.created` | A budget is created, including one created directly on a virtual key | `budget` |
| `gateway.budget.updated` | A budget's limit, scope or period is edited | `budget` |
| `gateway.budget.reset` | A budget's spend period is reset | `budget` |
| `gateway.budget.deleted` | A budget is archived | `budget` |
| `gateway.cache_rule.created` | A cache-control rule is created | `cache_rule` |
| `gateway.cache_rule.updated` | A cache-control rule is edited | `cache_rule` |
| `gateway.cache_rule.deleted` | A cache-control rule is archived | `cache_rule` |
| `gateway.guardrail.created` | A guardrail is created | `guardrail` |
| `gateway.guardrail.updated` | A guardrail is edited | `guardrail` |
| `gateway.guardrail.archived` | A guardrail is archived | `guardrail` |

Each row is written inside the same database transaction as the change it records, so a change either lands with its audit row or does not land at all.

Revoking a virtual key also archives the budgets scoped to that key, so a revocation writes a `gateway.virtual_key.revoked` row and one `gateway.budget.deleted` row per archived budget.

> [!NOTE]
>
> Attaching or detaching a guardrail writes two rows. The guardrail list is a field on the key, so the edit itself produces `gateway.virtual_key.updated`, and each added or removed guardrail produces its own `gateway.virtual_key.guardrail_attached` or `gateway.virtual_key.guardrail_detached` row carrying the guardrail id and its direction.

Reads are not logged. For read attribution, use the trace on each request, which carries the virtual key that made the call. See [Observability](https://langwatch.ai/docs/ai-gateway/observability.md).

## Reading the log in the app

The Audit Log page is at **Settings, Audit Log**. It needs the `auditLog:view` permission at the organization and the Enterprise plan.

Filter by user name or email, by action code, by project, and by date range. All gateway codes start with `gateway.`, so typing `gateway.` in the action filter narrows the page to gateway rows.

Every virtual key and every budget detail page has an **Audit history** button. It opens the Audit Log page filtered to that resource, and the filter shows as a chip you can clear. The button stays available on a revoked key and on an archived budget, so a forensic review starts from the resource itself.

## Querying programmatically

**Export CSV** on the Audit Log page downloads the rows the current filters select. The file carries these columns:

| Column | Content |
| - | - |
| `Timestamp` | ISO 8601 |
| `Source` | `gateway` or `platform` |
| `User Name`, `User Email` | The actor |
| `Action` | The action code |
| `Target Kind`, `Target Id` | The resource the action changed |
| `Project` | Project name, when the row names one |
| `IP Address`, `User Agent` | Request origin, on platform rows |
| `Error` | Error text, on platform rows |
| `Args` | Call arguments, on platform rows |
| `Before`, `After` | The gateway row's state on each side of the change |

You can reach the same data three ways:

1. **One-off, human review**: open `/settings/audit-log`, set the filters you want (Source, Action, Target), then hit **Export CSV** to download the filtered rows.
2. **Scripted, scheduled SIEM export**: query the Postgres `AuditLog` table directly from your SIEM ingestion pipeline. Filter on `targetKind IN ('virtual_key', 'budget', 'provider_binding', 'cache_rule')` to scope to gateway rows; join `User` on `userId` for actor enrichment.
3. **In-app integrations**: call the tRPC procedure from a TypeScript client that already has a session: `await trpc.organization.getAuditLogs.query({ organizationId, targetKind, targetId, since, limit })`. Mirrors what the UI does. Not intended for cross-network REST consumers.

`Args`, `Before` and `After` are JSON, capped at 4096 characters per cell. A capped cell ends with a `…[truncated N chars]` marker.

For a scheduled export into a SIEM, call the same query the Audit Log page uses: `organization.getAuditLogs`, at `GET /api/trpc/organization.getAuditLogs` with the input JSON in the `input` query parameter. It takes an `organizationId`, optional `projectId`, `userId`, `action` and `startDate`/`endDate` filters, and pages with `pageOffset` and `pageSize` up to 10000. It checks `auditLog:view` at the organization every call, so the export carries the same authorization as the page.

There is no REST endpoint for audit rows. Reading the `AuditLog` table in the application Postgres database is possible on a self-hosted deployment that owns the database, and it enforces no permission of its own, so keep it for operators who already hold database credentials. Filter on `organizationId` first, because that column is what separates one organization's rows from another's, then on `targetKind IN ('virtual_key', 'budget', 'cache_rule', 'guardrail')` for gateway rows, and join `User` on `userId` for the actor.

For a governance event feed, see [OCSF export](https://langwatch.ai/docs/ai-gateway/governance/ocsf-export.md), which carries trace and anomaly events rather than these audit rows.

## Retention and integrity

Rows live in the application Postgres database, indexed on `(organizationId, createdAt)` and on `(targetKind, targetId)`, which is what keeps both the organization-wide view and the per-resource view fast.

The application only ever inserts into this table. It exposes no update and no delete path, so a row that lands stays as written.

**Also check:** [Virtual Keys](https://langwatch.ai/docs/ai-gateway/virtual-keys.md) for the rotation and revocation operations behind those action codes, [RBAC](https://langwatch.ai/docs/ai-gateway/rbac.md) for who can read the log, [Security](https://langwatch.ai/docs/ai-gateway/security.md) for the rest of the security boundary.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.