# Audit log

The audit log says who did what, on what, on whose behalf, and with what result. This page explains what it contains, how to read and export it from the console, by an agent or through the API, how long it is kept, and what guarantees it has not been rewritten.

## What is logged

Every call to a platform operation writes a line, whether allowed, refused or in error, whether it comes from the console, the command line, the API or an agent. On top of that come actions of the platform itself (a deferred deletion, a second-factor reminder) and those of a Glowsoft operator under an access to your project (see [Security](security.md)).

A line as read carries:

| Field | Meaning |
| --- | --- |
| `occurredAt` | The instant, to the microsecond. |
| `actorType` | `human` (a person), `agent`, `service` (a service account) or `system` (the platform). |
| `actorId` | The account, agent or token that acted. |
| `onBehalfOf` | For an agent or a service account: the person it acts for. |
| `action` | The operation, in the form `object.verb`: `deployment.create`, `member.manage`, `env.write.production`. |
| `result` | `allowed`, `denied` or `error`. |
| `denyReason` | For a refusal: its reason. |
| `target` | The targeted resource, typed (a project, a domain, a member…). |
| `changes` | For a change to project settings: each setting, its value before and after. |

What does not come out: the IP address, the user agent, the token's scopes, and the before and after state of anything other than a settings change. The log is there to tell who did what; it is not a copy of your data.

## Two logs that do not overlap

- **A project's log**: everything that names that project. It is read at the project's **Reader** rank, or with the **Security** role.
- **The organisation's log**: what names no project (members' roles, service accounts, mandatory second factor, GitHub connections, project creation). It is read at **Administrator** rank, or with the **Security** role.

An organisation Administrator therefore does not read, through this route, the log of a project where they hold no role. Together, the two make up everything the log holds for your organisation.

## Read from the console

In a project, open **Audit**: the "Journal d'audit" (audit log) screen lists lines from newest to oldest. The filter at the top picks "Tout" (all), "Refusé" (denied), "En erreur" (error) or "Autorisé" (allowed). Click a line for its detail; a settings change shows each value before and after, and says whether it required a redeployment. "Entrées plus anciennes" (older entries) loads the next page.

For the organisation, the **Membres** (Members) screen carries the "Journal de l'organisation" (organisation log) card with its latest lines.

## Read by an agent, the command line or the API

An agent reads a project's log with the `audit_read` tool:

```json
{
  "projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
  "result": "denied",
  "limit": 50
}
```

Parameters: `action` (one specific operation), `result`, `limit` (at most 100 per page), `cursor` for the next page. With `"source": "executions"`, the tool returns the project's agent executions and their detail: model, tools called, redacted inputs and outputs, tokens, cost, duration.

```sh
bastide audit read --project-id prj_01JQ8ZK4M7NP2RSTVWXYZ34567 --result denied
bastide organization audit read --organization-id org_01JQ8ZK4M7NP2RSTVWXYZ34567
```

The organisation's log has no MCP tool: it is read from the console, the command line or the API. References: [audit.read](../reference/operations/audit.read.md), [organization.audit.read](../reference/operations/organization.audit.read.md).

## Export

Export is free on every tier, in three formats. It is the same route as reading, requested with the `Accept` header:

| Format | `Accept` header |
| --- | --- |
| NDJSON, one line per entry | `application/x-ndjson` |
| CSV | `text/csv` |
| JSON | `application/vnd.bastide.export+json` |

```sh
curl https://api.bastide.app/v1/projects/prj_01JQ8ZK4M7NP2RSTVWXYZ34567/audit \
  -H "Authorization: Bearer $BASTIDE_TOKEN" \
  -H "Accept: text/csv" -o audit.csv
```

The export returns the whole requested log as one file, without a cursor, under the filters passed. Each line is checked against the published schema before it leaves; a non-conforming line stops the file rather than going out wrong.

In the console, "Exporter" (export, on the **Audit** screen) downloads the project's log as NDJSON under the filter shown, and "Exporter le journal" (export the log, on the **Membres** screen) downloads the organisation's.

## How long it is kept

The price list sets the length of a project's log by tier:

| Découverte | Standard | Pro | Souverain |
| --- | --- | --- | --- |
| 30 days | 12 months | 24 months | 36 months |

Today the platform keeps the log for **three years** on every tier, in whole monthly partitions, and reading does not yet apply the grid's limits. No purge erases a partition less than three years old.

## What guarantees its integrity

- **Append only.** The log is not modified: a written line is neither rewritten nor erased by the platform.
- **Chaining.** Each entry carries a hash computed together with the previous entry's hash. Removing or altering an entry breaks the chain, and the check names the first faulty line. This check is a Glowsoft operations tool that walks the whole chain.
- **Copy outside the platform.** The platform can deposit a daily copy of the log with a second French operator, in write-once storage that not even a platform administrator can delete before three years. This copy depends on the installation's configuration.

Actions of the Glowsoft team at platform level are kept in a separate operations log, also chained, that you do not read. What an operator does on your data under an access does go into your project's log.

> **Note.** Forwarding the audit stream to your own monitoring tool (SIEM) cannot be set up yet: no screen or operation configures it.

## Common errors

| Code | What happens | What to do |
| --- | --- | --- |
| `insufficient_rank` | You have neither the required rank nor the Security role. | Ask an Administrator for the Security role. |
| `curseur_expire` | The pagination cursor has expired. | Start reading again from the beginning. |
| `curseur_invalide` | The cursor was not issued by this server, or it was altered. | Pass `nextCursor` unchanged. |

See also: [Security](security.md), [Organisations and members](organizations.md), [Logs](logs.md), [Agent safety](agent-safety.md).
