How It Works
Webhooks let you receive automatic notifications when events occur in Veridox, such as a file analysis completing.1
Create a webhook configuration
Someone with
organisation_settings:write creates a webhook configuration, providing a destination URL where you want to receive events.2
Store your signing secret
Veridox provisions a signing secret (format:
whsec_{32-char-alphanumeric}) and returns it once in the creation response. After that, only a prefix is shown for identification.3
Receive events
When events occur, Veridox sends a
POST request to your URL with:- A JSON payload in the body
- An
x-vdx-timestampheader holding the time the request was sent, in Unix seconds - An
x-vdx-signatureheader containing an HMAC-SHA256 hex digest, signed with your webhook secret over the timestamp and the body; see Signature Verification
4
Verify and process
You verify the signature and the timestamp on your server to confirm the request genuinely came from Veridox, hasn’t been tampered with, and isn’t an old request being replayed, then process the event.
Event Types
Analysis failures are not currently delivered to configured webhook endpoints. To detect a file that did not complete, poll the file’s
analysis_status via List Files or subscribe to case progress.
Every payload carries an
event_type. Branch on it rather than assuming a single shape, so that new event types added later do not break your receiver.Delivery Semantics
Responding
Keep your response inside the 30-second window and hand the event to your own code for anything slower. What matters is only this:- Return
2xxonce you have taken responsibility for the event. This stops redelivery. - Return any non-
2xx, or nothing at all, if you could not accept it. This asks for a retry, and you have roughly 24 hours of them.
Because a non-
2xx simply schedules the next attempt, returning an error while you are unavailable is safe. The same event comes back every 30 minutes until you accept it.Payload Structure
The example below is abridged; arrays are truncated and some sections are collapsed. See the Webhook Payload Reference for every key, its type and an example value.Absent keys versus null
Handling these two cases wrongly is the most common integration bug:- Optional top-level sections may be absent, or present with the value
null. This applies toresults,integrity_signals,highlights,ocr_summary, andtrace_id. Treat both forms identically and use a null-safe accessor. - Nested keys are always present, carrying
nullwhere a step did not apply to the file. Everything insideanalysis_metadata,artifacts,file_info, and each module follows this rule. caveatsandmodulesare always arrays, nevernull.previously_seen_atis absent rather thannullwhenpreviously_seenisfalse.
Field notes
Module Evidence
Each entry inmodules carries its findings alongside the evidence that supports them:
The two carry different weight and are kept separate for that reason.
search_evidence is web research with a synthesised answer, so it is corroborative. verification_evidence is a direct check against an authoritative source, so it is definitive. Show them distinctly to your reviewers rather than combining them into one evidence list.
A finding’s evidence_refs are IDs that point back into its module’s evidence, so you can resolve each claim to its source:
- IDs like
q1.1resolve againstsearch_evidence.results, matched onresult_id. The trailing index is 1-based and matches the[1]citation markers in the query’sanswer. - IDs like
v1resolve againstverification_evidence.checks, matched oncheck_id.
results.search_evidence_summary and results.verification_evidence_summary objects roll the same evidence up across modules, keyed by module_id, which is useful for rendering an overview without walking every module.
Both summary objects may be
null, and a query’s answer may be null. Treat them as optional when parsing.Analysis Caveats
Thecaveats array records limits on how far an analysis should be trusted, such as an authoritative source being unreachable or text recognition quality being poor. Each caveat carries a severity of info, warn, or critical.
A critical caveat on an otherwise clean analysis is the case worth surfacing to your reviewers: it means the clean verdict itself is not dependable. See caveats for every field.
Signature Verification
Thex-vdx-signature header is computed as:
- Read the
x-vdx-timestampheader and reject the request if it is more than five minutes away from your current time. - Compute the HMAC over the timestamp, a
., and the raw request bytes. - Compare it against the
x-vdx-signatureheader using a timing-safe comparison.
event_id to recognise a repeat.
Signature scheme change
Previously,x-vdx-signature was an HMAC over the raw body alone, which does not protect against a replayed request. It now uses the timestamped form above.
The samples below accept either form while ACCEPT_BODY_ONLY_SIGNATURE is on, which let you change over without missing a webhook. Turn ACCEPT_BODY_ONLY_SIGNATURE off: leaving it on keeps accepting old requests that were captured before the switch, which is exactly what the timestamp exists to prevent.
A receiver that still verifies the body-only form alone will reject webhooks.
- Node.js
- Python
Best Practices
Store secrets securely because the signing secret is shown once at creation time and cannot be retrieved again
Always verify signatures against the raw request bytes before doing anything with the payload
Reject stale requests whose
x-vdx-timestamp is more than five minutes from your current timeUse timing-safe comparison to prevent timing attacks
Respond within 30 seconds, and do slower work outside the request
Recognise repeat deliveries using
event_id, which is the same on every retry of an eventIgnore keys you do not recognise so that keys added later do not break your receiver
Only one active webhook configuration is allowed per organisation at a time. Creating a new configuration deactivates the previous one.