Proof Systems & Verification
AdPriva produces three kinds of signed records. Each one is sealed when it is created and anchored on Horizen later. This page explains how each is sealed and who can check it.
Record types
| Record | Created when | Sealed with | Anchored as | Who can check it |
|---|---|---|---|---|
| View proof | The tag reports a page load | An HMAC-SHA256 with AdPriva’s private key. The signature is the proof id | A Poseidon Merkle root, anchored on Horizen | Only AdPriva can check the HMAC. Anyone can check batch membership against the anchored root |
| Consent certificate | A visitor submits a form marked data-adpriva-consent | An HMAC over the site, form URL, consent-wording hash, checkbox state, timestamp and nonce | A SHA-256 Merkle root, anchored on Horizen | Only AdPriva can check the HMAC. Anyone can check batch membership against the anchored root |
Consent Evidence certificate (cert_v: 1) | A visitor submits a form that declares a registered Legal Bundle (data-adpriva-bundle) | An Ed25519 signature over the certificate’s canonical JSON (RFC 8785) | Anchored with the consent certificates | Anyone, offline, with AdPriva’s published public key |
For consent records, see Consent Certificates — Quickstart and Verifying a Consent Evidence Certificate.
Checking a view proof
- Look up the proof id in the Explorer, or call
GET https://api.adpriva.com/public/proofs/{proof_id}. No account is needed. - Read its status, validity score and verdict. Once the proof is batched, the response also carries a Merkle inclusion receipt:
leaf,leaf_index,merkle_path,merkle_path_indicesandhash_version. - Recompute the batch root from the leaf and the path. The API Reference has the algorithm for each
hash_version. - Compare your root with the
Anchored(merkleRoot)event in thehorizen_txtransaction. - For a batch anchored before 2026-09-28, you can also open
zkverify_urlto see zkVerify’s check of the batch’s zero-knowledge proof. New batches have none (zkverify_statusisNOT_APPLICABLE). See Legacy: zero-knowledge step.
Steps 3 and 4 do not rely on AdPriva’s status field. They work offline once you have the receipt and the transaction.
Shortened example response (merkle_path is cut down here; the real path has 20 entries):
{
"proof_id": "dcea8f8ef8f162c6b7269dd4d1ad24708f6358cbd6fa6d48dd528ab0e5e29b08",
"type": "view",
"status": "verified",
"merkle_root": "0x05f559a4dbb3c8f4cce6434b3e933468cc23a1c5bba2c479275d3349254d5e5c",
"leaf": "6485",
"leaf_index": 2,
"merkle_path": ["18928760214379673151198604163469262720598047531616892520656806346189907746915", "20057140030177622096707912563671758214552331126762024679885238248733466757272", "0", "…", "0"],
"merkle_path_indices": [0, 1, 0, "…", 0],
"hash_version": "poseidon",
"zkverify_status": "NOT_APPLICABLE",
"horizen_status": "CONFIRMED",
"horizen_tx": "0x846be1b73a220942c73e04d4772df04a4ca8b19b008cd9ce00aed0d2911ea885",
"validity_score": 100,
"verdict": "human"
}
What sealing and anchoring guarantee
| Guarantee | How | Limit |
|---|---|---|
| A captured event cannot be counted twice | The server refuses a nonce it has already seen, and the database refuses a second proof with the same signature | It does not stop someone from sending a new event with a fresh nonce. Scoring is what judges those |
| A view proof’s sealed fields cannot be changed unnoticed | The HMAC covers the event type, the site, the nonce and the browser’s timestamp. Changing any of them gives a different signature, and the signature is the proof id | Only AdPriva holds the HMAC key. The seal does not cover the score, the verdict or the other stored fields |
| A batch’s members are fixed in time | The batch’s Merkle root is in a Horizen transaction | For view batches (hash_version: "poseidon"), each leaf is the proof’s internal number, which the public API returns with the receipt. The root does not cover a proof’s score or verdict. A proof is pending until its batch is anchored |
| A consent record’s content is fixed in time | Consent batches use the certificate signatures as leaves, and each signature is computed over the certificate’s content | The seal does not cover the personal fields, which are erased at expiry. See Data-Processor Posture §4 |
| A consent certificate can be checked without AdPriva | Ed25519 signature and published key (cert_v: 1 and the record-only cert_v: 2) | Older consent certificates use the HMAC seal |
Anchoring shows that a record was in its batch when the batch was anchored. It does not show that a person was behind the event, and it does not fix a view proof’s score or verdict. See Proofs of Engagement for how verdicts are given.
{% @mermaid/diagram content="flowchart LR
A\[Tag: view event or consent form]
B\[Ingest server: nonce check and seal]
C\[Database]
D\[Anchor worker: Merkle batch]
E\[Horizen: Anchored event]
F\[Public API and Explorer]
A --> B
B --> C
C --> D
D --> E
C --> F" %}