prev_hash field. The record’s own hash is then computed over a canonical serialisation that includes prev_hash. This means tampering with any historical record would break the chain at every subsequent record — detectable in O(n) by a single verify_chain call. The chain is append-only and per-org: each organisation has its own sequence, cross-tenant interference is structurally impossible, and verifying one org’s chain never touches another’s data.
The first record an organisation writes uses prev_hash = "0" * 64 as a sentinel genesis. From there, every new record extends the chain by exactly one link.
How hashing works
Hashing runs on a canonical JSON encoding of eight specific fields:sort_keys=True, separators=(',', ':'), ensure_ascii=False, UTF-8 encoded, and SHA-256 digested. The hex digest is the record’s hash. Because the recipe is deterministic and language-independent, a Python SDK caller and a TypeScript caller producing the same logical record compute bit-identical hashes.
Fields not included in the hash
The following fields are stored on the record but are not part of its hash identity:id— assigned server-side at insert; not under the caller’s control.hash,created_at— computed or stamped during persistence; not inputs to the hash.alternatives,human_in_loop,meta— caller-supplied metadata free to evolve in future versions without invalidating the chain.
Verifying the chain
The SDK does not yet wrap the verify endpoint. Call it directly via REST.is_valid: true response is constant-time small regardless of how many records passed — verification is cheap enough to run on a cron.
What the response contains
| Field | Type | Description |
|---|---|---|
is_valid | boolean | true if the entire chain is intact. |
records_checked | integer | Number of records walked before stopping. |
first_broken_link | string | The id of the first record where the hash did not match, if any. |
What the chain does not do
It does not prove a decision happened at a specific wall time
It does not prove a decision happened at a specific wall time
Timestamps are SDK-produced. A malicious writer with a valid API key could backdate a record. If you need non-repudiable time, add an external timestamping service such as RFC 3161 or a public blockchain anchor on top of the chain.
It does not prove the decision was correct
It does not prove the decision was correct
The chain proves a record exists as written and has not been altered since. Whether the decision itself was right or wrong is a business question — not something cryptographic integrity can answer.
It is not proof against key compromise
It is not proof against key compromise
An attacker with write access to your API key can still insert records at the tip of the chain. The hash chain makes retroactive tampering detectable, not prospective injection. Rotate API keys promptly if you suspect a compromise.