# Auditing the Event Store

This guide explains how to **audit the integrity of events stored in EventSourcingDB**. Using the audit endpoint, you can verify that the event chain has remained unchanged, ensuring **tamper-proof compliance** and reliable **historical data integrity**.

## How Event Chain Auditing Works

EventSourcingDB stores events in an **immutable, append-only log**. Each event contains a cryptographic hash referencing its predecessor, forming a secure, verifiable chain **similar to a blockchain**.

When performing an audit, EventSourcingDB:

- **Calculates the cryptographic hash** for each event.
- Verifies that each event's hash **matches the predecessor hash** stored in the subsequent event.
- If provided, checks that a previously audited event's ID and hash match exactly, ensuring that **no past events were tampered**.

This mechanism enables external auditors to regularly confirm the integrity of stored events, reducing the audit scope to newly added events since the last verification.

For detailed information on event storage and consistency, see **[Consistency Guarantees](/docs/eventsourcingdb/v1.2/consistency-guarantees)**.

## Performing an Audit

*(Changed in 1.3)* To audit the event store, send an HTTP `POST` request to the **`/api/v1/audit-history`** endpoint.

### Initial Audit

When performing an audit for the first time, **no request body is required**:

```shell
curl \
  -i \
  -X POST \
  -H "Authorization: Bearer <API_TOKEN>" \
  http://localhost:3000/api/v1/audit-history
```

### Subsequent Audits

If you previously audited the store, include the **`latestEventId`** and **`latestEventHash`** from the last successful audit. EventSourcingDB will verify the integrity starting from the first event **up to and including the given event ID**, and **continue with all subsequent events**:

```shell
curl \
  -i \
  -X POST \
  -H "Authorization: Bearer <API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
        "latestEventId": "<PREVIOUS_EVENT_ID>",
        "latestEventHash": "<PREVIOUS_EVENT_HASH>"
      }' \
  http://localhost:3000/api/v1/audit-history
```

Replace **`<PREVIOUS_EVENT_ID>`** and **`<PREVIOUS_EVENT_HASH>`** with the actual values from your last audit.

## Interpreting Audit Results

*(Changed in 1.3)* The server responds with a **stream of newline-delimited JSON**. While the audit is still running, the server sends **[`heartbeat` lines](/learn/tutorials/first-steps-with-eventsourcingdb/observing-events)** to keep the connection open; the **final line carries the result**.

If the audit succeeds, the result holds the ID and hash of the latest event audited, **confirming the integrity of the entire event chain up to this point**:

```json
{"type":"result","payload":{"latestEventId":"...","latestEventHash":"..."}}
```

*(Changed in 1.3)* **Writes wait while the audit runs**, until it has finished, and so do reads that arrive after a waiting write.

*(Changed in 1.3)* If the store is empty, the payload is **an empty object `{}`**.

If the provided event ID or hash does not match, or if the event chain has been tampered with, the stream ends with an `error` line instead, whose message describes the issue:

```json
{"type":"error","payload":{"error":"..."}}
```

The stream also ends with an `error` line if the audit itself cannot run to completion. The status code is already **200** by the time the first line goes out, so **the last line is what tells you whether the audit succeeded**. Treat an `error` line as a failed audit, not as a clean one.

*(Removed in 1.3; Broken in 1.2, fixed in 1.3)* **An event that is older than the event before it fails the audit** as well, as a chain that has been tampered with does. Such an event comes about when the clock of the server goes back while it writes, for example when NTP corrects it, and the audit fails from it on.

If the audit found a mismatch or a tampered chain, **further investigation is required**. Review logs, check the last known good state, and consider **running a full store verification** as described in **[Verifying Store Integrity](/docs/eventsourcingdb/v1.2/verifying-store-integrity)**.

## Typical Use Cases

Auditing the event store is **crucial whenever strong guarantees about historical integrity are required**. Typical scenarios include **external compliance audits**, where auditors must independently verify that no historical data was tampered. Regular audits are also useful in internal governance processes to maintain trustworthiness of data over time.

In industries like finance, healthcare, or public services, audit trails are often a legal requirement, and the ability to **efficiently validate the event history** is essential. Additionally, audits provide a valuable tool in dispute resolution, enabling teams to prove that critical business events **have not been manipulated** after the fact.

## Best Practices

*(Changed in 1.3)* It is recommended to **perform audits regularly** and **securely archive** the `latestEventId` and `latestEventHash` values returned from each successful audit. This allows subsequent audits to be incremental, focusing only on the newly added events.

Automating the audit process, for example as part of scheduled maintenance routines, helps **ensure consistent verification without manual overhead**.

Whenever an audit fails, **immediate investigation** should be triggered, as **any detected tampering could indicate a serious security incident or systemic issue**. For comprehensive data integrity management, it is advisable to **combine regular auditing** with **full store verifications** as described in **[Verifying Store Integrity](/docs/eventsourcingdb/v1.2/verifying-store-integrity)**.

Auditing provides a lightweight but powerful mechanism to protect the **long-term trustworthiness** of event-sourced data and to **demonstrate compliance** with security, legal, and operational standards.
