# Audit log

> The audit log records changes to your organization and who made them. These endpoints read it, so you can send the events to your own security tools.

Canonical HTML page: https://conclude.io/doc/api/audit-log/
Last updated: 2026-10-27

---

**The API is in beta.** API keys are available to organizations in the beta program. Requests and responses may still change, and we tell beta customers before they do. [Contact us](https://conclude.io/contact/) to get access.

The audit log records changes to your organization and who made them. These endpoints read it, so you can send the events to your own security tools.

Reading the audit log needs the scope `audit:read`. The person the token acts for must be an admin of your organization. A key that acts as Conclude counts as an admin.

## List events

`GET /v1/auditEvents` · scope `audit:read`

Returns one page of events, newest first. Every parameter is optional. Conclude rejects an invalid value instead of ignoring it.

| Parameter | Description |
|---|---|
| `limit` | The number of events on a page, from 1 to 500. The default is 50. A larger value returns 500. |
| `category` | Only events in these [categories](#categories). Separate several with commas, as in `key,signIn`. |
| `type` | Only events of this one [type](#categories), such as `apiKey.issued`. |
| `actor` | Only events made by this user, as a user ID such as `U-3b5d7f9h`. |
| `from` | Only events at or after this time, in RFC 3339 format. |
| `to` | Only events before this time, in RFC 3339 format. |
| `position` | The `nextPosition` from the previous page. |

URL-encode every value. A `+` in a time offset or in `position` otherwise reads as a space.

```sh
curl -G https://api.conclude.io/v1/auditEvents \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  --data-urlencode "category=key" \
  --data-urlencode "from=2026-10-01T00:00:00Z"
```

```json
{
  "events": [
    {
      "id": "1287",
      "type": "apiKey.issued",
      "category": "key",
      "date": "2026-10-27T14:03:12.52Z",
      "actor": {
        "kind": "user",
        "user": {
          "id": "U-3b5d7f9h",
          "name": "Kim Lee",
          "email": "kim.lee@example.com",
          "accounts": [{"platform": "slack", "platformID": "U07ABCDEF12"}]
        }
      },
      "summary": "Issued API key Helpdesk",
      "refs": {},
      "details": [
        {
          "key": "scopes",
          "label": "Scopes",
          "value": ["connections:readwrite", "org:read"],
          "text": "connections:readwrite, org:read"
        },
        {"key": "expiry", "label": "Expires", "value": "2027-10-27T00:00:00Z", "text": "2027-10-27"},
        {"key": "global", "label": "Acts as Conclude", "value": true, "text": "yes"}
      ]
    }
  ],
  "nextPosition": "MjAyNi0xMC0yN1QxNDowMzoxMi41Mlp8MTI4Nw=="
}
```

To read the next page, send the same request with `position` set to `nextPosition`. On the last page, `nextPosition` is empty.

| Status | Code | When |
|---|---|---|
| 400 | `invalid_request` | A parameter has an invalid value. `param` names it. |
| 403 | `forbidden` | The person the token acts for is not an admin, or your organization is not in the beta program. |

## Get an event

`GET /v1/auditEvents/{auditEvent}` · scope `audit:read`

Returns one [event](#event-object). `{auditEvent}` is the event's `id`.

| Status | Code | When |
|---|---|---|
| 403 | `forbidden` | The person the token acts for is not an admin, or your organization is not in the beta program. |
| 404 | `not_found` | The event doesn't exist or is not in your organization's audit log. |

## The event object

| Field | Type | Description |
|---|---|---|
| `id` | string | The event's ID. |
| `type` | string | What happened. See [Categories and types](#categories). |
| `category` | string | The event's category. |
| `date` | time | When it happened. |
| `actor` | object | Who made the change. See below. |
| `summary` | string | A short English label for people. Don't parse it. |
| `refs` | object | What the event is about. See below. |
| `details` | array | Facts about the event. Each has a `key`, a `label`, the recorded `value` and a `text` for display. |
| `changes` | array | Settings the event changed. Each has a `field`, a `label`, a `before` and an `after` value. `block` is `true` for text that spans several lines. |
| `redacted` | boolean | `true` when the event names a private channel the token's person can't open. The channel then has no name or ID, and its details and changes are left out. |

`actor.kind` says who made the change:

| Kind | Who |
|---|---|
| `user` | A person, named in `actor.user`. |
| `apiKey` | An API key, named in `actor.apiKey` with its `id` and `name`. `actor.user` is the person the key acted for, when there was one. |
| `support` | Conclude support. |
| `system` | Conclude itself, for example a nightly job. |

A user has these fields:

| Field | Description |
|---|---|
| `id` | The user's ID. |
| `name` | The user's name. |
| `email` | The user's email address, when Conclude knows it. |
| `avatar` | The URL of the user's picture, when there is one. |
| `accounts` | The user's accounts in your Slack workspaces and Microsoft Teams tenants. Each has a `platform`, `slack` or `teams`, and the account's Slack or Microsoft Teams ID as `platformID`. |
| `leftOrganization` | `true` when the user no longer has an active account in any of your workspaces. |

`refs` can hold these fields:

| Field | Description |
|---|---|
| `channel` | The channel the event is about. |
| `remote` | The channel on the other side of a connection. |
| `channels` | The channels of a chat. |
| `user` | The user the event is about. |
| `org` | Another organization, with its `id` and `name`. |
| `workspace` | A workspace, with its `id`, `name`, `platform` and its Slack or Microsoft Teams ID as `platformID`. |
| `bridge` | A bridge, with its `id` and the partner `org`. |
| `agent` | An agent, with its `id`, `name` and `avatar`. `deleted` is `true` when the agent no longer exists. |

A channel has an `id`, a `name`, a `platform` and its Slack or Microsoft Teams ID as `platformID`. It also says whether it is `private` or `deleted`. It names its `team`, or its `org` when it belongs to another organization. The `team` is the Slack workspace or the team in Microsoft Teams, with its `id`, `name`, `platform` and `platformID`. A `redacted` channel only says where it is.

## Categories and types

| Category | Type | Summary |
|---|---|---|
| `account` | `organization.config.updated` | Changed the configuration |
| `account` | `organization.created` | Created the account |
| `account` | `organization.deleted` | Deleted the account |
| `account` | `organization.deletion.requested` | Requested deletion of the account |
| `account` | `organization.merged` | Merged another account into this account |
| `account` | `organization.updated` | Updated account settings |
| `account` | `workspace.added` | Added a workspace |
| `account` | `workspace.removed` | Removed a workspace |
| `user` | `organization.role.granted` | Gave a user a role |
| `user` | `organization.role.removed` | Took a role from a user |
| `user` | `user.hide` | Hid a user in the directory |
| `user` | `user.merge.blocked` | Couldn't merge two users, because both have accounts in one workspace |
| `user` | `user.merged` | Merged two users |
| `user` | `user.split` | Split a user into a separate account |
| `user` | `user.unhide` | Showed a user in the directory again |
| `signIn` | `user.signedIn` | Signed in to a workspace |
| `connection` | `connect.channel.created` | Connected two channels |
| `connection` | `connect.channel.deleted` | Disconnected two channels |
| `connection` | `connect.chat.created` | Connected a chat |
| `connection` | `connect.chat.deleted` | Disconnected a chat |
| `connection` | `connect.external.created` | Connected a channel with another organization |
| `connection` | `connect.external.deleted` | Disconnected a channel from another organization |
| `connection` | `connect.external.invitation.created` | Invited someone to connect a channel |
| `connection` | `connect.external.invitation.deleted` | Withdrew an invitation to connect a channel |
| `bridge` | `bridge.channel.connected` | Connected two channels on a bridge |
| `bridge` | `bridge.channel.disconnected` | Disconnected two channels on a bridge |
| `bridge` | `bridge.channel.published` | Shared a channel on a bridge |
| `bridge` | `bridge.channel.unpublished` | Stopped sharing a channel on a bridge |
| `bridge` | `bridge.chat.closed` | Closed a bridge chat |
| `bridge` | `bridge.chat.created` | Started a bridge chat |
| `bridge` | `bridge.created` | Started a bridge |
| `bridge` | `bridge.deleted` | Deleted a bridge |
| `bridge` | `bridge.disabled` | Paused a bridge |
| `bridge` | `bridge.enabled` | Resumed a bridge |
| `bridge` | `bridge.invitation.accepted` | Another organization accepted a bridge invitation |
| `bridge` | `bridge.invitation.created` | Invited someone to start a bridge |
| `bridge` | `bridge.invitation.deleted` | Withdrew a bridge invitation |
| `bridge` | `bridge.invitation.sent` | Sent a bridge invitation |
| `bridge` | `bridge.member.added` | Gave a user a role on a bridge |
| `bridge` | `bridge.member.removed` | Took a role on a bridge from a user |
| `app` | `app.installed` | Installed an app in a channel |
| `app` | `app.removed` | Removed an app from a channel |
| `app` | `app.updated` | Changed an app in a channel |
| `app` | `template.created` | Created a template |
| `app` | `template.deleted` | Deleted a template |
| `app` | `template.updated` | Changed a template |
| `agent` | `agent.created` | Created an agent |
| `agent` | `agent.deleted` | Deleted an agent |
| `agent` | `agent.deployed` | Added an agent to a channel |
| `agent` | `agent.mode` | Changed what an agent does in a channel |
| `agent` | `agent.removed` | Removed an agent from a channel |
| `agent` | `channel.learning` | Changed whether agents learn in a channel |
| `key` | `agent.key.budget` | Set the monthly budget of an AI provider key |
| `key` | `agent.key.removed` | Removed an AI provider key |
| `key` | `agent.key.set` | Set an AI provider key |
| `key` | `apiKey.issued` | Issued an API key |
| `key` | `apiKey.revoked` | Revoked an API key |
| `key` | `secret.created` | Added a secret |
| `key` | `secret.deleted` | Deleted a secret |
| `key` | `secret.updated` | Changed a secret |

A `type` outside the `category` you also give returns no events.

