EVIDE Payload Canonicalization
JSON does not guarantee key ordering. Two semantically identical JSON objects can produce different byte sequences — and therefore different SHA-256 hashes — if keys are serialized in a different order.
regardless of the order in which keys were submitted."
Without canonicalization, hash verification would be fragile: a developer rebuilding the payload from their system's internal representation in a different key order would obtain a different hash, making integrity verification impossible without the original byte stream.
Canonicalization solves this by defining a single deterministic normalization step that all implementations must apply before computing the hash. The result is that the hash becomes a property of the semantic content of the payload, not of its serialization order.
intake_hash returned in the API response is always the hash of the canonicalized form. Source systems implementing the same algorithm can compute the expected hash before submission and verify it against the returned value.
The EVIDE canonicalization algorithm consists of four steps applied in sequence:
content_hashcontent_hash field, remove it before any further processing. This field is a source-side pre-transit hash declaration — it must not be included in the canonical form, as doing so would create a circular dependency.\uXXXX escape sequences for non-ASCII characters). Forward slashes must not be escaped (/ not \/). The output encoding is UTF-8.json_encode($canonical, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)These two flags are required. Without
JSON_UNESCAPED_UNICODE, multi-byte characters are escaped as \uXXXX sequences, producing a different byte string. Without JSON_UNESCAPED_SLASHES, forward slashes in URLs are escaped as \/, again producing a different byte string.
The following tables show the alphabetical key order for the most relevant objects after canonicalization. These orderings are the result of standard lexicographic sort and are provided here as a reference to avoid implementation errors in common nested objects.
| # | Key |
|---|---|
| 1 | authority |
| 2 | chain |
| 3 | created_at_utc |
| 4 | decision |
| 5 | evide_schema |
| 6 | fedis_requested |
| 7 | handoff |
| 8 | human_oversight |
| 9 | intervention |
| 10 | object_class |
| 11 | source_reference |
| 12 | source_system |
| 13 | source_timestamp_utc |
| # | Key |
|---|---|
| 1 | taxonomy_reference |
| 2 | threshold_authority |
| 3 | threshold_reference |
| 4 | threshold_status |
| # | Key |
|---|---|
| 1 | readiness_gate |
| 2 | status |
| 3 | unresolved_signals |
| 4 | visibility_surface |
intake_hash returned by the API, the canonicalization is correct. Run this check on a known payload immediately after integration.The following example shows the same payload before and after canonicalization. The canonical form is what EVIDE hashes.
intake_hash returned by the API.Reference implementations of the EVIDE canonicalization algorithm. All three produce identical output for identical input.
JSON.stringify in all major JS engines does not escape forward slashes or non-ASCII characters by default, which is the correct behavior for EVIDE canonicalization. No additional flags are needed in JavaScript, unlike PHP.
The EVIDE integrity model consists of two complementary hash layers:
- content_hash (optional, source-declared) — the SHA-256 of the canonical payload computed by the source system before submission. If present, it extends the integrity chain to cover the full pre-intake transit: the source system commits to the payload content before the API ever receives it.
- intake_hash (mandatory, server-computed) — the SHA-256 of the canonical payload as received and stored by EVIDE. This is the authoritative fingerprint. It is returned in the API response and stored independently of the payload.
content_hash == intake_hash, the payload was not modified between source canonicalization and EVIDE intake. If they differ, at least one of: the payload was modified in transit, a different canonicalization was used on the source side, or content_hash was computed on the non-canonical form.
For FEDIS certification, the intake_hash is the value included in the forensic artifact. The source-declared content_hash is an optional integrity extension — useful for chain-of-custody documentation but not required for FEDIS issuance.
✓ Remove
content_hash before sorting✓ Sort keys recursively at every nesting level
✓ Minify with no whitespace
✓ Preserve Unicode characters as-is (no \uXXXX escape)
✓ Do not escape forward slashes
✓ Encode the string as UTF-8 before hashing
✓ Compare your output against the returned
intake_hash
EVIDE Minimum Intake JSON — Schema Reference: app.certifywebcontent.com/docs/evide-intake-schema/
Live JSON Schema: app.certifywebcontent.com/json
FEDIS Reference: certifywebcontent.com — FEDIS
EVIDE Signals & Roadmap: app.certifywebcontent.com/signals
The same content always produces the same fingerprint.