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

# Audit logs

> A queryable, principal-attributed record of control-plane actions.

The **audit log** is an append-only record of who did what on the control plane. Every sensitive mutation — an [agent](/docs/api/agents) update, a key rotation, a role change, a denied policy, a credit top-up — is captured as an immutable entry attributed to the acting **principal** (a member or an API key). Use it to answer "who changed this, when, and from which request?" for security review, incident response, and compliance.

Reads require the `audit:read` [scope](/docs/api/authentication#scopes). Entries are never modified or deleted; the log only grows.

## The audit entry object

<ResponseField name="id" type="string">Entry id (e.g. `aud_01H...`).</ResponseField>

<ResponseField name="actor" type="object">
  The principal that performed the action.

  <Expandable title="actor">
    <ResponseField name="type" type="string">`user` (a member acting in the dashboard) or `key` (an API key acting programmatically).</ResponseField>
    <ResponseField name="id" type="string">Id of the member (`usr_…`) or API key (`key_…`).</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="action" type="string">The audited action (see [Audited actions](#audited-actions)).</ResponseField>
<ResponseField name="resource_type" type="string">The kind of resource affected (e.g. `agent`, `api_key`, `member`, `webhook_endpoint`, `session`, `credits`).</ResponseField>
<ResponseField name="resource_id" type="string | null">Id of the affected resource, when the action targets one.</ResponseField>
<ResponseField name="request_id" type="string">The `x-request-id` of the request that produced the entry — join this to your own logs and to the [error envelope](/docs/api/errors).</ResponseField>
<ResponseField name="metadata" type="object">Action-specific detail (e.g. the before/after role on a role change, the `to_version` on a rollback, the denied tool on a policy denial).</ResponseField>
<ResponseField name="created_at" type="string">When the action occurred.</ResponseField>

## List audit logs

`GET /v1/audit_logs` returns entries newest-first. Cursor-paginated — see [Pagination](/docs/api/pagination).

### Filters

<ParamField query="actor" type="string">Filter to a single principal id (a member `usr_…` or key `key_…`).</ParamField>
<ParamField query="resource" type="string">Filter to a single resource id (e.g. a specific `agt_…`).</ParamField>
<ParamField query="action" type="string">Filter to one action string (e.g. `api_key.rotated`).</ParamField>
<ParamField query="from" type="string">Lower bound (inclusive) on `created_at`, an RFC 3339 timestamp.</ParamField>
<ParamField query="to" type="string">Upper bound (exclusive) on `created_at`, an RFC 3339 timestamp.</ParamField>

```bash theme={"system"}
curl -fsSL "https://api.vetta.sh/v1/audit_logs?action=member.role_changed&from=2026-08-01T00:00:00Z" \
  -H "authorization: Bearer sk_live_..."
```

<ResponseExample>
  ```json Response theme={"system"}
  {
    "data": [
      {
        "id": "aud_01H9MM...",
        "object": "audit_entry",
        "actor": { "type": "user", "id": "usr_01H8AA..." },
        "action": "member.role_changed",
        "resource_type": "member",
        "resource_id": "mem_01H9JJ...",
        "request_id": "req_01H9MM...",
        "metadata": { "from_role": "member", "to_role": "admin" },
        "created_at": "2026-08-20T18:02:11Z"
      },
      {
        "id": "aud_01H9ML...",
        "object": "audit_entry",
        "actor": { "type": "key", "id": "key_01H8XK..." },
        "action": "api_key.rotated",
        "resource_type": "api_key",
        "resource_id": "key_01H8XK...",
        "request_id": "req_01H9ML...",
        "metadata": { "reason": "scheduled_rotation" },
        "created_at": "2026-08-20T17:59:40Z"
      }
    ],
    "has_more": true,
    "next_cursor": "aud_01H9ML..."
  }
  ```
</ResponseExample>

## Audited actions

The following control-plane actions are captured in the initial release. The list grows over time; treat `action` as an open string and branch on the prefixes you care about.

| Action                   | Resource           | Recorded when                                                                                     |
| ------------------------ | ------------------ | ------------------------------------------------------------------------------------------------- |
| `agent.updated`          | `agent`            | An [agent](/docs/api/agents) configuration is changed (new version).                                   |
| `agent.rolled_back`      | `agent`            | An agent is rolled back to a prior version. `metadata.to_version` carries the target.             |
| `api_key.created`        | `api_key`          | A new [API key](/docs/api/authentication) is issued.                                                   |
| `api_key.rotated`        | `api_key`          | A key's secret is rotated.                                                                        |
| `api_key.revoked`        | `api_key`          | A key is revoked.                                                                                 |
| `member.role_changed`    | `member`           | A [member's](/docs/api/organizations) role changes. `metadata` carries `from_role`/`to_role`.          |
| `member.removed`         | `member`           | A member is removed (triggering the removal cascade).                                             |
| `policy.denied`          | `session`          | A [permission policy](/docs/api/agents) blocks a tool call (the persisted trace of a `403 forbidden`). |
| `credits.topped_up`      | `credits`          | A [top-up](/docs/api/credits) succeeds.                                                                |
| `webhook.secret_rotated` | `webhook_endpoint` | A [webhook](/docs/api/webhooks) signing secret is rotated.                                             |
| `session.interrupted`    | `session`          | A running [session](/docs/api/sessions) is interrupted.                                                |

<Note>
  Each entry pins the exact `request_id`, so an audited action, its [error envelope](/docs/api/errors) (if it failed), and your own request logs all correlate on one id. Money movements additionally carry an `actor` on the [ledger](/docs/api/credits#ledger), so spend is attributable without cross-referencing the audit log.
</Note>
