Building a DORA-Ready Audit Trail With Didit Webhooks
DORA expects financial firms to evidence what happened, when, and to whom across their ICT systems. Here's how to build a tamper-evident audit trail from Didit's verification webhooks — with a worked JSON example.

The Digital Operational Resilience Act (DORA) asks financial entities a deceptively hard question: can you prove what happened? When a supervisor investigates an incident, when an auditor samples your controls, or when a customer disputes an onboarding decision, you need a record — complete, time-stamped, and tamper-evident — of every event in your Information and Communication Technology (ICT) systems. Identity verification is one of those systems, and it generates exactly the events you need to capture.
This post is the practical one: how to turn Didit's verification and transaction webhooks into a DORA-ready audit trail, what to store, and how to make it stand up to scrutiny. It includes a worked webhook example you can build against today.
Key takeaways
- DORA expects evidence — a reliable record of ICT events for incident response, resilience testing, and supervisory review.
- Didit emits webhook events at every meaningful state change:
status.updated,data.updated,transaction.status.updated, andbusiness.status.updated. - Each event is a discrete, timestamped fact you append to an immutable log — the building block of an audit trail.
- Verify each webhook's signature, store the raw payload, and never mutate a logged record — append-only is the rule.
- Didit's own controls back the trail: SOC 2 Type 1 (ATOM), ISO/IEC 27001:2022 (cert nº ES144068), and iBeta Level 1 PAD — vendor-level assurance for your ICT third-party register.
- The result satisfies both the what-happened record DORA wants and the who-is-this proofing that underpins access control.
What the standard requires
DORA is built on five pillars: ICT risk management, incident reporting, digital operational-resilience testing, information-sharing, and ICT third-party risk management. An audit trail is the connective tissue across them. Specifically, financial entities need to:
- Detect, log, and report ICT-related incidents — which presupposes a record granular enough to reconstruct what happened.
- Test resilience, including the ability to trace transactions and events through the system.
- Manage third-party risk, including the records that flow from a provider like an identity-verification vendor.
- Retain records in a form that supervisors can request and rely on.
The implicit requirements of a usable audit trail follow from this: events must be complete (no silent gaps), accurate (faithful to what occurred), time-ordered (with reliable timestamps), attributable (tied to a subject and an actor), and tamper-evident (you can show a record wasn't altered after the fact).
Why it matters
When an incident happens — a suspected account-takeover, a disputed verification, a flagged transaction — the difference between a contained event and a regulatory problem is often the quality of your records. A complete trail lets you reconstruct the sequence, prove your controls fired as designed, and demonstrate to a supervisor that you handled it properly. A patchy trail leaves you guessing, and leaves the supervisor unconvinced.
Identity events are high-value here because they sit at the boundary of the system: the moment a person is verified, re-verified, or has their status change is exactly the moment you most want recorded. Capturing those events as they happen — rather than reconstructing them later from application logs — is what turns "we think this is what happened" into "here is what happened."
How Didit helps
Didit emits a webhook for every state transition in a verification, transaction, or business session. You don't poll; you receive a signed event the moment something changes.
| Event | Fires when | Audit value |
|---|---|---|
status.updated | A verification session changes status (e.g. to Approved, Declined, In Review) | Records the decision and its timing |
data.updated | Verified data on a session changes | Records what was captured/changed |
transaction.status.updated | A monitored transaction's status changes | Records monitoring decisions and analyst resolutions |
business.status.updated | A KYB business entity's status changes (ACTIVE/FLAGGED/BLOCKED) | Records business-onboarding outcomes |
Each event is a self-contained fact. Your job is to verify it, store it raw, and never change it. Together those events form an append-only ledger of everything Didit did on your behalf — the audit trail DORA wants for the identity-verification slice of your ICT estate.
And because Didit itself is attested — SOC 2 Type 1 (ATOM, as of 2026-04-09), ISO/IEC 27001:2022 (Bureau Veritas, cert nº ES144068, valid until 2027-06-03), and iBeta Level 1 PAD — the provider behind those events carries its own evidence for your DORA ICT third-party register.
Deep dive: turning a webhook into an audit record
Here's a status.updated webhook for a verification session that just resolved to Approved:
{
"event": "status.updated",
"session_id": "sess_7b21e0c4",
"vendor_data": "user_4521",
"status": "Approved",
"previous_status": "In Review",
"workflow_id": "wf_kyc_eu_substantial",
"checks": {
"id_verification": "passed",
"passive_liveness": "passed",
"face_match": "passed"
},
"created_at": "2026-05-21T10:32:04Z",
"signature": "t=1747824724,v1=9f86d081884c7d659a..."
}
To turn that into a DORA-ready audit record, do four things on receipt:
- Verify the signature. Recompute the HMAC over the raw request body using your endpoint's signing secret and compare it to the
signatureheader before you trust the payload. Reject anything that fails — an unverified event has no evidentiary value. - Store the raw payload verbatim. Persist the exact bytes you received, alongside your own ingestion timestamp. Don't normalize or reshape before storage; the raw event is the evidence.
- Append, never update. Write to an append-only store (or a table with no
UPDATE/DELETEgrants for the app role). If a later event supersedes an earlier one, write a new row referencing the oldsession_id— never overwrite. - Make it tamper-evident. Hash each record and chain the hash into the next (each row stores the previous row's hash), or write to a write-once store. Now you can prove the log wasn't altered after the fact.
The result is a chronological, attributable, tamper-evident ledger: for any session_id you can replay every state change, see which checks passed, and show exactly when the decision was made — and prove the record hasn't been touched since. That's the standard a supervisor or auditor is looking for, and it's the same pattern you'd apply to transaction.status.updated for monitoring decisions and business.status.updated for KYB outcomes.
Use cases
- Banks and EMIs building a DORA-aligned ICT event log that includes identity decisions.
- Crypto VASPs that must evidence onboarding and transaction-monitoring decisions to supervisors.
- Compliance teams preparing for resilience testing that traces events end-to-end.
- Engineering teams replacing brittle polling with signed, append-only event ingestion.
Frequently asked questions
Which webhook events should I capture for an audit trail?
At minimum status.updated and data.updated for verifications; add transaction.status.updated for transaction monitoring and business.status.updated for KYB. Capture every event — completeness is the point.
Do I need to verify webhook signatures?
Yes. An unverified webhook could be spoofed and has no evidentiary weight. Recompute the signature over the raw body and reject mismatches before logging.
Why append-only? Can't I just update a record when status changes?
DORA values tamper-evidence. If you overwrite records, you can't prove the history wasn't altered. Appending a new event for each change preserves the full, provable sequence.
Does capturing Didit's events satisfy all of DORA?
No — DORA is broad. Didit's events cover the identity-verification and monitoring slice of your ICT estate. You'll combine them with logs from the rest of your systems for a complete trail.
Does Didit have its own attestations for the DORA third-party register?
Yes — SOC 2 Type 1 (ATOM), ISO/IEC 27001:2022 (cert nº ES144068, valid until 2027-06-03), and iBeta Level 1 PAD, all available to support your vendor due diligence.
Ready to get started?
See Didit's attestations on the trust hub, read the webhook integration details in the docs, and review transparent pricing on the pricing page. When you're ready, start free — 500 free KYC checks every month, with a core verification flow from $0.33.