---
title: "Audit Journal"
description: "Read who did what in an organization: one entry per successful command, filterable by account, actor and free text."
canonical: https://developer.billabex.com/en/guides/audit-journal/
lang: en
alternate: https://developer.billabex.com/fr/guides/journal-d-audit/
last-updated: 2026-09-12
---

# Audit Journal

> Read who did what in an organization: one entry per successful command, filterable by account, actor and free text.

Source: https://developer.billabex.com/en/guides/audit-journal/
Language: English (en)
French version: https://developer.billabex.com/fr/guides/journal-d-audit/

Every successful command Billabex runs leaves one entry in the organization's
audit journal, whoever ran it: a person in the web app, a third-party client
through this API or the MCP server, the Billabex agent, or an internal system
path such as a connector synchronization.

An account's history is not a separate resource. It is this same journal scoped
to one account, which is also the only way to read the history of an account
that has been deleted.

## Endpoint

```http
GET /api/public/v1/organizations/{organizationId}/audit
```

Requires `organizations:read` or `organizations:all`.

| Parameter    | Type                                      | Description                                                                  |
| ------------ | ----------------------------------------- | ---------------------------------------------------------------------------- |
| `accountId`  | UUID                                      | Keep only the entries that acted on this account                             |
| `actorTypes` | `USER` \| `AGENT` \| `SYSTEM` \| `SERVICE_ACCOUNT`, repeatable | Keep only these kinds of actor                                               |
| `action`     | string                                    | Keep only this command name, for example `DeleteAccount`                     |
| `search`     | string                                    | Case-insensitive match in the recorded metadata, or on an audited account id |
| `page`       | integer                                   | Page to return, 1-based, defaults to 1                                       |
| `limit`      | integer                                   | Entries per page, defaults to 20, maximum 100                                |

Unlike the other list endpoints, this one paginates by page number rather than
by cursor. The journal is append-only and read newest first, so a page number is
stable enough, and it spares you a cursor for a list you mostly read the head of.

## Response

```json
{
  "nodes": [
    {
      "id": "f5183985-1f0e-4c2b-9a35-1a2b3c4d5e6f",
      "organizationId": "6effaee1-01d0-4205-b2da-911e28483dc6",
      "accountIds": ["78ce0186-2b4f-4b1c-9c3a-0d1e2f3a4b5c"],
      "actorType": "USER",
      "actorId": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed",
      "actorFullName": "Marie Dupont",
      "actorEmail": "marie@example.com",
      "actorDeleted": false,
      "actorChannel": "WEBAPP",
      "actorSource": null,
      "action": "DeleteAccount",
      "metadata": "{\"accountId\":\"78ce0186-2b4f-4b1c-9c3a-0d1e2f3a4b5c\"}",
      "createdAt": "2026-08-27T19:40:35.542Z"
    }
  ],
  "totalCount": 1,
  "page": 1,
  "limit": 20,
  "totalPages": 1
}
```

### Reading an entry

- `accountIds` lists every account the command acted on. A bulk action over two
  hundred accounts is **one** entry carrying two hundred ids, not two hundred
  entries. An organization-wide action, such as changing a setting, carries an
  empty array.
- `actorType` says who: `USER` for a person, `AGENT` for the Billabex agent,
  `SYSTEM` for an internal path.
- `actorChannel` is set for a person and says which door they came through:
  `WEBAPP`, `PUBLIC_API` or `MCP`.
- `actorSource` is set for a system actor: `CONNECTOR`, `SCHEDULER`, `WEBHOOK`,
  `ADMIN_API`, `MIGRATION`, `WORKFLOW` or `INTERNAL`.
- `actorDeleted` is `true` only for a user known to have been deleted. A missing
  name with `actorDeleted: false` means the projection has not caught up yet, not
  that the person is gone.
- `metadata` is the serialized command input, with `password`, `secret` and
  `token` values redacted. Beyond four thousand characters it is replaced by
  `{"truncated": true, "action": "..."}`.

## Finding an account that no longer exists

Once an account is deleted it is gone from every list, and its id alone tells you
nothing. Its name, however, survives in the metadata of the commands that touched
it. Search for the name, read the id off the `CreateAccount` entry, then scope the
journal to that id:

```bash
# 1. Find the account by name
curl -H "Authorization: Bearer $TOKEN" \
  "$BASE_URL/api/public/v1/organizations/$ORG/audit?search=CCOG&action=CreateAccount"

# 2. Read its whole history, including who deleted it
curl -H "Authorization: Bearer $TOKEN" \
  "$BASE_URL/api/public/v1/organizations/$ORG/audit?accountId=$ACCOUNT_ID"
```

`search` also matches the audited account ids, so pasting an id finds every
command that touched the account, including those whose own input never named it.

## MCP

The same journal is available to an MCP client as `list-audit-entries`, with the
same filters and the `mcp:read` scope.

## Limits

- The journal starts on 6 August 2026. Anything older was never recorded.
- Writing an entry is best-effort: it never fails the command it describes, so a
  missing entry means unattributed, never "did not happen".
- Commands that only maintain derived state are deliberately excluded, as are
  password and OAuth token commands.

---

Billabex developer portal. OpenAPI specification: https://developer.billabex.com/openapi.json.
Agent instructions: https://developer.billabex.com/llms.txt. Complete documentation: https://developer.billabex.com/llms-full.txt.
