audit-history
Audits the chain of events: checks that every event matches its hash and follows on the one before it, anchored at the event a previous audit ended at.
- Route:
POST /api/v2/management/audit-history - Category:
management - Authentication: required, with the API token
- Answer: a stream of NDJSON
Every event names the hash of the event before it, so the events form a chain of hashes. An audit checks that chain from the first event up to the latest one at its start, and checks that the event the previous audit ended at still has the hash it had then, so a successful audit confirms that nothing has changed up to the previous one. Writes go on while it runs, and the events they add are left for the next audit. A restore does not end an audit: the audit waits until the restore is over. Auditing the Event Store explains how to audit regularly and what to do when an audit fails.
Request#
The body is a JSON object, with the content type application/json:
| Field | Type | Required | Meaning |
|---|---|---|---|
lastAuditedEvent |
object or null |
yes | The event the previous audit ended at, or null for a first audit. It has no default: a body that leaves it out is refused rather than taken for a first audit, so that an audit that has lost its anchor does not skip checking it. |
lastAuditedEvent.id |
string | yes, unless lastAuditedEvent is null |
The ID of that event, a non-negative integer in a string, without a sign or a leading zero, such as "41". |
lastAuditedEvent.hash |
string | yes, unless lastAuditedEvent is null |
The hash of that event: 64 lowercase hexadecimal digits, prefixed with esdb:hash:v2: for a hash of version 2. |
Send the id and hash exactly as the lastAuditedEvent item of the previous audit named them. To audit the store, anchored at the event 0 that a previous audit ended at:
curl \
-X POST \
-H "authorization: Bearer secret" \
-H "content-type: application/json" \
-d '{
"lastAuditedEvent": {
"id": "0",
"hash": "esdb:hash:v2:3fe219db06819ac40fd287a9cde02c071e9ee4b846bb262dd5b7c67569c2dc66"
}
}' \
http://localhost:3000/api/v2/management/audit-history
Answer#
The answer is a stream of items, one per line. A successful audit ends with a lastAuditedEvent item:
| Type | Data | When |
|---|---|---|
lastAuditedEvent |
id and hash of the latest event audited |
Once, before the end item, when the audit succeeded and the database holds events. Keep it as the anchor of the next audit. |
error |
code, description, and details |
When the audit fails, or cannot run, see Errors. |
heartbeat |
empty | While nothing else is sent for a while, to keep the connection alive. |
end |
empty | Once, as the last item, when the stream ends cleanly. |
Heartbeats and the end item work as on every stream of the API, see Streams. A first audit of a database without events is answered with the end item alone, and the next audit sends null again. The audit succeeded only if the stream ends with the end item and holds no error item.
For a database that holds the events 0 and 1, the request above is answered with:
{"type":"lastAuditedEvent","data":{"id":"1","hash":"esdb:hash:v2:32f739af34b563c90aa33fc47d39a061db72091aa0fd83c70a322b51bea5f22a"}}
{"type":"end","data":{}}
Errors#
The audit reports these errors as an error item, followed by the end item:
last-audited-event-missing: The request leaves outlastAuditedEvent.event-id-missing:lastAuditedEventleaves out itsid, or gives an empty one.event-id-malformed: Theidis not a non-negative integer in a string, without a sign or a leading zero, such asforty-oneor041.event-hash-missing:lastAuditedEventleaves out itshash, or gives an empty one.event-hash-malformed: Thehashis not a hash, such as one that was cut short.last-audited-event-mismatched: The event with thatidhas another hash in the database, so the events changed since the previous audit, or the anchor does not come unchanged from this database.last-audited-event-unknown: The database holds no event with thatid. This is reported only once the whole chain was checked.event-chain-broken: An event does not follow on the one before it, or does not match its hash, so the stored events were changed or damaged.event-hash-version-unknown: An event has a hash of a version that this version does not know.file-unreadable: A file of the store that the audit needs is damaged, such as an events file whose checksum no longer matches.store-failed: The store refuses reads for good, after a restore that could not empty it again.server-shutting-down: The server began to shut down after the audit had sent a heartbeat. Before that, the server answers with503instead.
Status Codes#
Before the stream begins, the server answers with a status code other than 200 where it cannot take the request at all, as described in Errors:
400: The content type of the body is notapplication/json, or the body is no JSON object of the shape above, for example an empty body, a field the route does not know, such aslatestEventIdof the v1 API,nullas theidorhash, or anidgiven as a number rather than a string.401: The API token is missing or wrong.408: The body did not arrive in time.413: The body is larger than its limit.429: Too many requests were sent, or the client already holds 256 open streams, see Rate Limiting; the answer says when to try again.500: The server failed unexpectedly before the stream began. Once it has begun, the stream breaks off without itsenditem instead.503: The server is shutting down, or began to shut down before the stream began.