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

# Audit API

> Read your Granola workspace's audit log programmatically.

The Audit API exposes your workspace's audit log — a record of who did what and when, suitable for compliance and auditability concerns.

[`GET /v1/audit`](/api-reference/list-audit-events) returns your workspace's audit events, newest first. It returns only the actions listed in the [audit events reference](/audit-events). Actions are added over time, so treat `action` as an open set of strings rather than a fixed list.

## What you can answer with it

Most compliance and investigation questions map to a small group of actions. Start here, then see the [full event reference](/audit-events) for the fields each action carries.

| Question                                                   | Actions                                                                                                                                                     |
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Which meetings was someone in while Granola was recording? | `transcription.started`, `transcription.ended` — both carry the calendar event ID, `null` for a recording that was not on the calendar                      |
| Who opened a note, or its transcript?                      | `document.viewed`, `transcript.viewed`                                                                                                                      |
| Who can reach a note, and who changed that?                | `document.access_granted`, `document.access_revoked`, `document.user_role_changed`, `document.sharing_link_visibility_changed`                              |
| Who joined or left the workspace?                          | `workspace.member_added`, `workspace.member_joined`, `workspace.member_removed`, `workspace.member_left`, `workspace.member_role_changed`                   |
| Who signed in, and from what device?                       | `auth.login`, `auth.login_failed`, `auth.logout`, `auth.session_revoked`                                                                                    |
| How were API keys and MCP used?                            | `workspace.public_api_key_used`, `workspace.public_api_key_first_used`, `mcp.tool_used`, `mcp.token_enabled`, `mcp.token_regenerated`, `mcp.token_disabled` |
| What data left Granola?                                    | `data_export.requested`, `data_export.succeeded`, `notes.transfer_out`, `integration.*_connected`                                                           |

`action` matches an exact action or a prefix ending at a dot, so most groups are one call: `?action=transcription`, `?action=auth`, `?action=mcp`. The boundary is strict — `document` excludes `document_list`, `workspace` excludes `workspace_automation`, and note views span two prefixes, so they are two calls.

Each action has a defined scope, including which platforms report it. See [Before you start](#before-you-start) for exactly what each one records before relying on it.

## Getting access

The Audit API is available on Enterprise plans. A workspace admin creates an Audit API key in **Settings → Connectors → Audit API keys**.

An audit key reads the audit log and nothing else. It cannot list or fetch notes, folders, spaces, or webhook endpoints — those endpoints report that they do not exist when called with an audit key. Because the key belongs to the workspace rather than to the admin who created it, it keeps working after that person leaves.

## Before you start

### Up to five audit keys per workspace

A workspace can have up to five active audit API keys at a time, so each system reading the audit log can hold its own key and be cut off on its own. To rotate a key, create its replacement first and then revoke the old one, so nothing reading the audit log is interrupted. Creating a sixth key while five are active is rejected.

### Event availability

The Audit API serves events from the last year. An event older than that is no longer returned.

How far back an action reaches varies, and history is never backfilled. Treat the oldest event you see for an action as the start of the data available to you, not as when that kind of activity began. A field added to an existing action is `null` on events recorded before it existed.

`occurred_after` and `occurred_before` must both fall inside the one-year window. A date further back is rejected with a `VALIDATION_ERROR` naming the earliest date you can ask for.

If your retention requirements are longer than a year, pull events into your own system on an ongoing schedule rather than treating this endpoint as the archive.

### Account events belong to a member, not a workspace

Six actions describe a member's Granola account rather than your workspace: `auth.login`, `auth.logout`, `auth.session_revoked`, `auth.sessions_revoked`, `auth.calendar_linked` and `user.email_changed`.

They appear in your feed because the person was an active member of your workspace when the event happened, not because the action was aimed at your workspace. A sign-in authenticates an account rather than entering your workspace, and the calendar account connected or email address changed may be a personal one. Use these events for offboarding and account hygiene rather than as a record of activity inside your workspace.

Client details describe the member's own device: `context.ip_address`, `context.user_agent` and `context.client_version`, plus a coarse `data.location` and `data.deviceInfo` on `auth.login`. They are reported by the client rather than verified, and every workspace receives the same values.

The feed covers only members you share, and only while their membership is active. After someone leaves, their later sign-ins no longer appear; events from while they had access are kept.

### View events cover authenticated reads only

Only reads by a signed-in user are recorded: `document.viewed` from the desktop and web apps, and `transcript.viewed` from the desktop app. A note opened through a share link by someone who is not signed in is never recorded, because there is no account to name as the reader. Other surfaces do not report reads yet either, so the absence of a view event is not evidence a note was not read.

### MCP tokens belong to a member, not a workspace

An MCP token authenticates the member who created it, and reads one workspace at a time: whichever workspace that member currently has active in Granola. A `mcp.*` event is recorded against the workspace they had active when they changed the token, so it tells you a member enabled, replaced or removed an MCP credential — not that the credential is confined to your workspace, and not that every credential able to reach your workspace appears here.

For new `mcp.tool_used` events, `clientName` and `clientVersion` are the connecting software's best-effort, self-reported values, not an authenticated client identity. `context.ip_address` is the source address observed by Granola's serving infrastructure when one was available; client-supplied forwarding headers are not trusted. Existing events are not backfilled, so these fields are `null` on older rows.

### Pagination and throughput

`page_size` returns at most 30 events per page. Page on `hasMore` and `cursor`, not on how many events a page contains: a page can hold fewer events than you asked for and still not be the last one.

Events are ordered by `collected_at` — when Granola recorded the event — newest first, not by `occurred_at`. The two differ for events we learn about after the fact: a meeting recording is recorded once its summary finishes, and a note viewed offline is recorded when that device next reaches us. That means a page can contain an event whose `occurred_at` is older than one you saw on an earlier page, so use `occurred_at` to reason about when something happened and `collected_at` to reason about your position in the feed.

The rate limit is shared with every other API key in the workspace, so a backfill should be paced rather than parallelised. See [Rate limits](/introduction#rate-limits).

### Event IDs are opaque

An event's `aud_` ID is an opaque, stable identifier: it is not a UUID, and it carries no ordering or timestamp meaning. Store it as a deduplication key, but do not parse it or sort by it.

### Field naming

A field in `data` that references another resource holds a prefixed ID string, the same as `parent_folder_id` does elsewhere in this API: `"documentId": "not_1d3tmYTlCICgjy"`, not a nested object.

### What can change

Actions are added over time, and so are the fields inside an action's `data`. Ignore an action or a field you do not recognise rather than failing on it.

What will not change without a new API version: an existing field's meaning, and its presence. A value Granola did not record, or recorded in a form it could not read, is returned as `null` rather than dropped, so an action's key set is the same on every one of its events.

## Next steps

* [Audit events reference](/audit-events) — every action the endpoint can return, and the fields each one records.
* [`GET /v1/audit`](/api-reference/list-audit-events) — query parameters, response shape, and examples.
