Skip to main content

How It Works

Every event in Immutable is linked to the previous event in a per-workspace SHA-256 hash chain. This creates a tamper-evident seal across your entire audit trail — if any event is modified, inserted, or deleted at the database level, the chain breaks and the tampering is detectable.
The first event in a workspace has previous_event_hash set to null.

Hash Computation

Each event hash is a SHA-256 digest computed from all event fields:
Metadata keys are recursively sorted and targets are sorted by type then id before hashing. This ensures deterministic hashes regardless of JSON key order or array ordering in the database.

Chain Ordering

Events are chained by created_at (server-side timestamp with microsecond precision), not occurred_at (client-provided time). This guarantees a consistent, linear chain even when clients report out-of-order timestamps.

Concurrency Safety

Immutable uses PostgreSQL advisory locks (pg_advisory_xact_lock scoped by workspace ID via crc32) to ensure concurrent event ingestion does not produce conflicting hash chains. Only one event per workspace is hashed at a time.

Integrity Block

Every event returned by the API includes an integrity block:

Verifying the Chain

Use the verify endpoint to validate the entire chain or a date range:
See Hash Verification for programmatic monitoring.

Break Types

If tampering is detected, the breaks array describes each issue:
Legacy events ingested before hash chain activation have nullable hash fields. The verify endpoint skips these events and does not report them as breaks.

Batch Event Ordering

When events are ingested via the batch endpoint, each event’s created_at is offset by 1 microsecond to preserve insertion order. Without this offset, batch events would share the same created_at value and UUID-based ordering would not match insertion order, causing false chain_break errors during verification.