Legal · v1.1
Effective date: 13 October 2026 · Last updated: 17 October 2026
This page is for the data protection officer, works council or privacy reviewer of a ComplyEdge customer. It lists every field ComplyEdge stores for each decision, why, for how long, where, who can read it, and how it is erased. It complements the Data Processing Agreement and the Privacy Policy; where they differ, the signed DPA governs.
Each time your AI system calls ComplyEdge, one audit record is written. It never contains the text that was checked. It holds a keyed hash of that text (HMAC-SHA-256 under a key that belongs to your account and never leaves ComplyEdge), the rule that decided, the decision, and, only if you send them, a pseudonym of the user and session and the user's role. Records expire after 184 days. Deleting your account destroys the key, after which no stored hash or pseudonym can be linked to an input or a person.
| Field | What it holds | Why |
|---|---|---|
event_id | Random identifier of the decision | Lets you cite one record, for example in a complaint answer |
tenant_id | Your account identifier | Keeps your records apart from every other customer's |
api_key_id | Identifier of the API key that made the call (never the key itself) | Shows which of your integrations made the call |
agent_id | The name you give your AI system | Shows which system the decision was about |
direction | Whether the text was a prompt, a model output or an action the AI system was about to take | The same rule applies differently to each |
text_hash | Keyed hash (HMAC-SHA-256) of the checked text | Proves which text a decision was about without storing it |
text_hash_alg | hmac-sha256-1; absent on records written before the keyed hash was deployed, whose hash is a plain SHA-256 | Tells a verifier how to check the hash |
pseudonym_key_version | Which generation of your account key was used | A record keyed before an erasure cannot be confused with one keyed after |
jurisdiction | The legal regime applied, for example EU | Article 5 of the EU AI Act applies only in the EU |
bundle_id, bundle_digest | Version and content digest of the rule set | Shows exactly which rules decided |
timestamp | When the decision was made, UTC | Record-keeping duty; the order records are exported in |
allowed, action | The decision | The point of the record |
violations, violation_ids, violations_count, violation_detected | Which rules fired, with their legal citation, severity, rule version, the provision of law each enforces and whether the rule is approved; a code, never a model's sentence, where a model gave the reason | Explains the decision |
exemptions, rejected_exemptions | Exemptions claimed for the call and whether each was accepted | Explains why a rule did or did not apply |
art12_purposes | Which record-keeping purposes the record serves | Maps the record to EU AI Act Article 12 |
engine_path, model_used, confirm_model, layer2_skipped, overridden_hits | Which engine decided; the model, when the optional Layer 2 review ran or was skipped | Shows whether a deterministic rule or a model decided |
latency_ms | How long the decision took | Service quality and incident analysis |
user_id | A keyed pseudonym (p1:…) of the user identifier you send; nothing if you send none | Lets you answer an access request or investigate one case, without storing who it is |
session_id | A keyed pseudonym of the session identifier you send; nothing if you send none | Groups the decisions of one conversation or run |
user_role | The role you send, stored as sent, for example recruiter | Risk by role; must name a role, never a person |
subject | A keyed pseudonym of the reference you send for the person the decision is about; nothing if you send none | Lets you find one person's decisions for an access or objection request |
correlation_id | A keyed pseudonym of the exchange identifier you send; nothing if you send none | Ties the check of a request to the check of its answer |
subject_is_employee, works_agreement_ref | Whether the person is your employee, and a reference to the agreement that permits these records, as you send them | Employee monitoring rules apply to such records |
deciding_system_version | The version of your AI system or model, as you send it | Shows which version of your system the decision was about |
purpose_ref, data_categories | Your reference to the purpose of the processing, and the categories of personal data the decision used, from a fixed list, as you send them | Ties the record to your processing record; shows special categories |
decision_mode | How automated the decision was (solely_automated, decisive, advisory, or human), as you send it when the decision is about a person | Records the role of the AI system for the person's rights |
notice | That the person was informed about use of the AI system: whether notice was given, when, your notice reference, and for employees when workers were informed | Shows the person was told, without storing the notice text |
explanation_inputs | References and codes captured at decision time so a later explanation can be produced without the checked text (logic, procedure, main factors, risks, main elements) | Lets you answer an explanation request later from the record alone |
withheld, escrow_ref | Whether disclosure to the person was withheld on trade-secret or third-party grounds, and your reference under which that material can be produced to a supervisor or court | Records a lawful withhold without storing the withheld text |
legal_basis | The provision of law you name as the basis of a decision about a person, as you send it | Shows the basis without restating your assessment |
source_ref | Your own locator of the checked text in your systems, as you send it; never the text | Lets you find the text for an access request or an authority, where you keep it |
region | Where the record is stored | Shows data residency on the record itself |
schema_version | Record format version | Lets old and new records be read correctly |
ttl | The moment the record expires | Enforces the retention period automatically |
retention_class, retention_erase_after | The retention that applies, for example retention-184d, and the date after which the record is erased | States the retention on the record itself |
event_type | logging_failure on a record that says a decision or a timestamp could not be recorded; oversight on a record of a person's review (below); legal_hold on a hold placed or lifted over a range of the chain; contest, notice, incident, opt_out, classification or fallback on event records written through the audit API; absent on decision records | A failure to record is itself recorded, never silent; a hold, rights, classification or fallback event is its own record |
hold | On a legal_hold record: the hold id, placed or lifted, the chain sequence scope, and an optional reason code | Says which records must not be destroyed until the hold is lifted |
decision_ref, request_kind, requested_at, responded_at, reviewer, review_outcome, statement_ref, rectified_at | On a contest record: which decision was contested, what was asked, when, and when answered the keyed reviewer pseudonym, outcome, statement reference, and rectification time if any | Records the person's request and the answer without storing the statement text |
notice_kind, channel_ref, language, issued_at | On a notice event record: kind of notice issued to the person, channel, language, when issued, plus decision_ref and statement_ref | Shows a rights notice was issued without storing its text |
incident_kind, detected_at, reported_at, report_ref | On an incident record: kind of incident, when detected and reported, and your report reference | Records risk, modification, serious incident or suspension for the deciding system |
decision_ref, reason_code | On an opt_out record: optional reference to the decision whose recording was suppressed, and an optional reason code | Records that a lawful user opt-out stopped a check from being written |
classification_result, assessment_ref | On a classification record: whether the system was assessed as high-risk or not, and your reference to that assessment | Records an Article 6(3)/(4) classification without storing the assessment text |
fallback | On a fallback record: kind (skipped, degraded, fallback_engine, timeout) and a reason code | Records that a check was not run normally |
chain_seq | Position of the record in your account's chain: 1, 2, 3 and so on, with no gaps | A missing number shows a record was removed |
chain_prev | The chain_hash of the record written just before this one | Ties each record to the one before it, so a reordered or inserted record shows |
chain_hash | SHA-256 of chain_prev followed by this record in its ADCR 0.1.0 canonical form, computed as the record is written | A record edited later no longer matches the hash it carries |
chain_alg | sha256-chain-1; absent on records written before the chain existed, which an export labels pre_chain | Tells a verifier how to recompute chain_hash |
When the account holder finishes the review of a flag in the dashboard (found a violation, or found the output compliant), one more record is written on the same chain, with the chain, retention and event_type fields above and these:
| Field | What it holds | Why |
|---|---|---|
proposal_ref | The event_id of the decision record that was reviewed | Links the person's action to the system's decision without changing it |
oversight_action, reason_code | accepted with layer2.reviewed_violation, or disregarded with layer2.reviewed_compliant | What the person decided, as a code |
reviewer | A keyed pseudonym (p1:…) of the email address the reviewer signed in with | Shows who reviewed without storing the address |
reviewer_role, authority_ref | account_holder, and the address of the review authority statement | States the reviewer's role and where their authority comes from |
review_opened_at, inputs_ref | When the flag was raised, and the dashboard address of the flag | Shows what the reviewer was shown, and since when |
The record also carries its event_id, tenant_id, timestamp and pseudonym_key_version. When the decision reviewed names an agent, it carries that agent_id, and the decision's deciding_system_version when the decision recorded one. The review notes are kept on the flag, with the same reviewer pseudonym, and never on the audit record. Sending a flag to legal counsel writes no record.
Not stored: the checked text, any excerpt of it, and any identifier in raw form. A value shaped like a password, token or API key sent as a user or session identifier is replaced before the record is written.
text_hash is HMAC-SHA-256 under that key of the checked text, prefixed with commitment: so it can never equal a pseudonym. Unlike a plain hash, nobody without the key can test guesses against it, so a short or predictable input cannot be recovered from it.user_id, session_id, subject, correlation_id and reviewer become p1: followed by 32 hex characters, computed the same way with the field name as the prefix. The same person always gets the same pseudonym within your account, so one person's records can be found on request, and a different customer's pseudonym for the same identifier is unrelated.user_role is not pseudonymised. Send a role, never a name.audit_key_ciphertext (the KMS-encrypted key), audit_key_version, audit_key_created_at, and audit_key_shredded_at once a key has been destroyed. The audit archive never copies the encrypted key.You never need the key. To prove a record was about a specific text, send the text and the event_id to POST /v1/audit/verify; the answer is yes or no, and the text is not stored or logged. To find one person's records, send their identifier to POST /v1/audit/pseudonym and search your export for the result. Both are described in the API reference. Each record is appended to your account's hash chain as it is written (the four chain_ fields above). Once an hour the current end of the chain is timestamped by Sectigo, an eIDAS-qualified provider that receives only a hash. That timestamp request carries only the chain position and hash, never a record, a hash of a text or a pseudonym. Exports on the Enterprise plan include the chain fields and the hourly timestamps, so a third party who trusts neither you nor us can check offline that no record was altered, removed, reordered or inserted after it was written. Records written before the chain existed are labelled pre_chain and are not claimed.
Because the record never holds the text, the controller keeps the text: store the event_id returned by each check next to your own copy of the prompt or answer, and check the pair with POST /v1/audit/verify when an audit or a complaint needs it. How audit reconciliation works explains the steps and what happens if you delete your copy early.
The customer is the controller and chooses the legal basis. The ones we expect controllers to rely on are: the security of processing (GDPR Art. 32), because the record shows that harmful or unlawful AI output was blocked; and, from 2 December 2027, for deployers of high-risk AI systems, a legal obligation (GDPR Art. 6(1)(c)) under EU AI Act Art. 26(6), which requires logs to be kept for at least six months. ComplyEdge acts as processor under the DPA.
| Copy | Kept for | What it holds |
|---|---|---|
| Audit record | 184 days | The fields above. Enterprise accounts may lengthen this, never shorten it. |
| Write-once archive of each change | 180 days | Locked against deletion for this period, so evidence cannot be removed while it must be kept |
| Archive deletion | 400 days | Archive copies are deleted after this |
| Chain timestamp anchors | 400 days | Each hourly qualified timestamp over your chain (position, hash and token, no record content) is locked against deletion for at least this period; longer when your retention is longer |
| Anchor deletion | 3660 days | Anchors whose lock has lapsed are deleted after this |
| Database point-in-time recovery | 35 days | Restore points of the database, for disaster recovery |
| Weekly backups | 210 days | Backup copies of the database, for disaster recovery |
| Application logs | 90 days | Operational logs. They never contain the checked text or a hash of it. |
| Logs of the public rule-check tool | 14 days | Operational logs of the free offline-check service |
Records written before pseudonymisation reached production may still hold the user identifier in the form it was sent until they expire; the live records were rewritten to pseudonyms, while the archive and backup copies of those older records age out on the periods above.
You choose the region when you create your account: the EU region (Frankfurt, Germany, eu-central-1) or the US region (Oregon, United States, us-west-2). Records, keys, archive and backups stay in that region. Sub-processors are listed in section 6 of the DPA; the optional Layer 2 model review sends the checked text to OpenAI only when you turn it on.
Records are readable by your account through the dashboard and API, and by ComplyEdge staff with access to the production cloud account, for support and incident response, under confidentiality (DPA §5.2). Because records hold no text and no raw identifiers, staff cannot see what was checked or who it was about. The account key can be used only by the service, for your account.
key_shredded_at), exports name the same date (audit_key_shredded_at), and new records use a new key. A restore from a backup taken before the destruction could bring the old key back for as long as that backup exists (up to 210 days); we do not restore an erased key into a live account.Adapt this for the employees whose work your AI system supports, and for your works council:
Our AI assistant is checked by an external compliance service, ComplyEdge, before it acts. For each check, ComplyEdge keeps a record of the decision and the rule applied for 184 days. The record does not contain what was written. If we pass an identifier for you, it is stored as a code that cannot be traced back to you without our key. The records are used to show regulators and auditors that the assistant was checked, and to investigate a specific incident. They are not used to rank or assess individual employees. Contact [your DPO] for questions or to exercise your rights.
Questions from a data protection officer or works council: support@complyedge.io.