How It Works
Every event in Immutable is part of a per-workspace SHA-256 hash chain. Each event’s hash is computed from all of its fields plus the hash of the previous event. Change any field on any event, and every subsequent hash in the chain breaks.previous_event_hash set to null. Every subsequent event references the hash of its predecessor.
The 22 Hashed Fields
Every field on the event is included in the hash computation. Nothing is excluded.| Group | Fields |
|---|---|
| Identity | workspace_id |
| Actor | actor_id, actor_name, actor_type |
| Action | action, action_category |
| Resource | resource_id, resource_name, resource |
| Context | metadata, targets, occurred_at |
| Network | ip_address, ip_country, ip_city, user_agent |
| Tracking | tenant_id, session_id, idempotency_key, version |
| Chain | previous_event_hash |
SHA-256 over the result.
Deterministic ordering matters. Metadata keys are recursively sorted and targets are sorted by
type then id before hashing. This guarantees identical hashes regardless of JSON key order or array ordering in the database.How Tampering Is Detected
Field modification (hash_mismatch)
If any field on an event is modified — even a single character in the metadata — the recomputed hash will not match the stored hash.Event insertion or deletion (chain_break)
If an event is inserted into or deleted from the chain, theprevious_event_hash on the next event will not match the hash of what now precedes it.
Chain Ordering
Events are chained bycreated_at (server-side timestamp with microsecond precision), not occurred_at (client-provided time). This guarantees a linear, consistent chain even when clients submit events with out-of-order timestamps.
When events are ingested via the batch endpoint, each event’s
created_at is offset by 1 microsecond to preserve insertion order. Without this, batch events would share the same timestamp, and UUID ordering would not match insertion order — causing false chain breaks during verification.